summaryrefslogtreecommitdiff
path: root/source/Test/Unit
diff options
context:
space:
mode:
authoradelon <22380201+adelon@users.noreply.github.com>2026-08-06 17:54:00 +0200
committeradelon <22380201+adelon@users.noreply.github.com>2026-08-06 17:54:00 +0200
commit82328890108bae64b372b8d58620ebc62699de76 (patch)
tree575404c6b425c19259c0ded296f1c8ffb7ff0e2b /source/Test/Unit
parent1a25421c2a168d420581358c8733fcd8f36f379b (diff)
Migrate to `Felix` namespaceHEADhotg
Diffstat (limited to 'source/Test/Unit')
-rw-r--r--source/Test/Unit/Abstract.hs114
-rw-r--r--source/Test/Unit/Backend.hs752
-rw-r--r--source/Test/Unit/CommandLine.hs799
-rw-r--r--source/Test/Unit/Concrete.hs221
-rw-r--r--source/Test/Unit/Core.hs670
-rw-r--r--source/Test/Unit/Declaration.hs3596
-rw-r--r--source/Test/Unit/Foundation.hs284
-rw-r--r--source/Test/Unit/Html.hs225
-rw-r--r--source/Test/Unit/HtmlLayout.hs478
-rw-r--r--source/Test/Unit/HtmlOutput.hs560
-rw-r--r--source/Test/Unit/Identity.hs802
-rw-r--r--source/Test/Unit/Kernel.hs858
-rw-r--r--source/Test/Unit/Lexicon.hs333
-rw-r--r--source/Test/Unit/Materialization.hs357
-rw-r--r--source/Test/Unit/Meaning.hs1119
-rw-r--r--source/Test/Unit/Module.hs9759
-rw-r--r--source/Test/Unit/OutputPlan.hs236
-rw-r--r--source/Test/Unit/Provers.hs1159
-rw-r--r--source/Test/Unit/Semantic.hs437
-rw-r--r--source/Test/Unit/Source.hs2581
-rw-r--r--source/Test/Unit/Store.hs1675
-rw-r--r--source/Test/Unit/Token.hs285
22 files changed, 0 insertions, 27300 deletions
diff --git a/source/Test/Unit/Abstract.hs b/source/Test/Unit/Abstract.hs
deleted file mode 100644
index 61118bd..0000000
--- a/source/Test/Unit/Abstract.hs
+++ /dev/null
@@ -1,114 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Unit.Abstract (unitTests) where
-
-import Base
-import Report.Location
-import Syntax.Abstract
-
-import Hedgehog
-import Hedgehog.Gen qualified as Gen
-import Test.Tasty
-import Test.Tasty.HUnit hiding (assert)
-import Test.Tasty.Hedgehog (testPropertyNamed)
-
-unitTests :: TestTree
-unitTests =
- testGroup "Abstract syntax"
- [ testPropertyNamed
- "noun phrase ordering obeys the Ord laws"
- "prop_nounPhraseOrd"
- prop_nounPhraseOrd
- , testCase
- "noun phrase fields survive ordered deduplication"
- nounPhraseFieldsRemainDistinct
- ]
-
-prop_nounPhraseOrd :: Property
-prop_nounPhraseOrd = withTests 100 . property $ do
- x <- forAll nounPhrase
- y <- forAll nounPhrase
- z <- forAll nounPhrase
-
- (compare x y == EQ) === (x == y)
- compare x y === oppositeOrdering (compare y x)
- assert (not (x <= y && y <= z) || x <= z)
-
-nounPhraseFieldsRemainDistinct :: Assertion
-nounPhraseFieldsRemainDistinct =
- assertEqual
- "one value per base and changed field"
- 6
- (length
- (nubOrd
- [ sampleNounPhrase False False False False False
- , sampleNounPhrase True False False False False
- , sampleNounPhrase False True False False False
- , sampleNounPhrase False False True False False
- , sampleNounPhrase False False False True False
- , sampleNounPhrase False False False False True
- ]))
-
-nounPhrase :: Gen (NounPhraseOf Maybe Int)
-nounPhrase =
- sampleNounPhrase
- <$> Gen.bool
- <*> Gen.bool
- <*> Gen.bool
- <*> Gen.bool
- <*> Gen.bool
-
-sampleNounPhrase
- :: Bool
- -> Bool
- -> Bool
- -> Bool
- -> Bool
- -> NounPhraseOf Maybe Int
-sampleNounPhrase hasLeft otherNoun hasName hasRight hasSuchThat =
- NounPhrase
- [AdjL Nowhere leftAdjective [1] | hasLeft]
- (Noun
- Nowhere
- (if otherNoun then secondNoun else firstNoun)
- [2])
- (NamedVar "x" <$ guardMaybe hasName)
- [AdjR Nowhere rightAdjective [3] | hasRight]
- (truthStatement <$ guardMaybe hasSuchThat)
- where
- guardMaybe condition =
- if condition then Just () else Nothing
-
-leftAdjective :: LexicalItem
-leftAdjective =
- mkLexicalItem [Just (Word "left")] "left"
-
-rightAdjective :: LexicalItem
-rightAdjective =
- mkLexicalItem [Just (Word "right")] "right"
-
-firstNoun :: LexicalItemSgPl
-firstNoun =
- mkLexicalItemSgPl
- (SgPl
- [Just (Word "first")]
- [Just (Word "firsts")])
- "first"
-
-secondNoun :: LexicalItemSgPl
-secondNoun =
- mkLexicalItemSgPl
- (SgPl
- [Just (Word "second")]
- [Just (Word "seconds")])
- "second"
-
-truthStatement :: Stmt
-truthStatement =
- StmtFormula (PropositionalConstant Nowhere IsTop)
-
-oppositeOrdering :: Ordering -> Ordering
-oppositeOrdering = \case
- LT -> GT
- EQ -> EQ
- GT -> LT
diff --git a/source/Test/Unit/Backend.hs b/source/Test/Unit/Backend.hs
deleted file mode 100644
index 5243c96..0000000
--- a/source/Test/Unit/Backend.hs
+++ /dev/null
@@ -1,752 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Unit.Backend (unitTests) where
-
-import Base hiding (Empty)
-import Checking.Backend.Problem
-import Checking.Backend.Tptp
-import Checking.Core
-import Checking.Foundation qualified as Foundation
-import Felix.Provers
-import Tptp.UnsortedFirstOrder qualified as Tptp
-
-import Data.Map.Strict qualified as Map
-import Data.Text qualified as Text
-import Data.Vector (Vector)
-import Data.Vector qualified as Vector
-import Numeric.Natural (Natural)
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-data TestGlobal
- = FirstOrderPredicate
- | HigherOrderPredicate
- deriving (Show, Eq, Ord)
-
-testGlobalType :: TestGlobal -> Maybe CoreType
-testGlobalType = \case
- FirstOrderPredicate ->
- Just (TySet `TyArrow` TyProp)
- HigherOrderPredicate ->
- Just
- ((TySet `TyArrow` TyProp)
- `TyArrow` TyProp)
-
-data TestLocal
- = ObjectLocal
- | PredicateLocal
- deriving (Show, Eq, Ord)
-
-unitTests :: TestTree
-unitTests =
- testGroup "Typed backend problem"
- [ testCase
- "projects proposition equality as equivalence"
- classifiesPropositionEquality
- , testCase
- "projects exact ambient support"
- projectsExactAmbientSupport
- , testCase
- "routes implicit, explicit, and local-only problems"
- routesCompleteProblems
- , testCase
- "admits only checked implicit set constructions"
- admitsImplicitSetConstructions
- , testCase
- "renders checked FOF and TH0 problems"
- rendersCheckedProblems
- ]
-
-classifiesPropositionEquality :: Assertion
-classifiesPropositionEquality = do
- proposition <-
- checkedProposition
- Vector.empty
- (CEq TyProp CFalsum CFalsum)
- capability <-
- either
- (assertFailure . show)
- pure
- (classifySupportedProposition
- testGlobalType
- proposition)
- case capability of
- FofProjectable{} ->
- pure ()
- RequiresTh0 exclusions ->
- assertFailure
- ("proposition equality was not projected: "
- <> show exclusions)
-
-projectsExactAmbientSupport :: Assertion
-projectsExactAmbientSupport = do
- let term :: CanonicalTerm Void
- term =
- CForall TySet
- (CEq TySet
- (CBound 1)
- (CBound 3))
- scoped <-
- either
- (assertFailure . show)
- pure
- (checkScopedCanonicalCore
- (const Nothing)
- [TySet, TySet, TySet]
- term)
- projected <-
- either
- (assertFailure . show)
- pure
- (projectSupportedProposition
- (const Nothing)
- (Vector.fromList
- [ (0 :: Int, TySet)
- , (1, TySet)
- , (2, TySet)
- ])
- scoped)
- assertEqual
- "unused middle support is removed"
- (Vector.fromList
- [ (0 :: Int, TySet)
- , (2, TySet)
- ])
- (supportedPropositionSupport projected)
- assertEqual
- "indices are remapped below nested binders"
- (CForall TySet
- (CEq TySet
- (CBound 1)
- (CBound 2)))
- (supportedPropositionTerm projected)
-
-routesCompleteProblems :: Assertion
-routesCompleteProblems = do
- fofFact <-
- checkedBackendFact
- (0 :: Int)
- firstOrderClaim
- th0Fact <-
- checkedBackendFact
- (1 :: Int)
- higherOrderClaim
- let fofFacts =
- Vector.singleton fofFact
- th0Facts =
- Vector.singleton th0Fact
- claim <-
- checkedProposition
- (Vector.singleton
- (ObjectLocal, TySet))
- (CApp
- (CGlobal FirstOrderPredicate)
- (CBound 0))
- firstOrderLocal <-
- checkedLocalPremise
- 0
- "first-order local"
- claim
- higherOrderLocalProposition <-
- checkedProposition
- (Vector.singleton
- (PredicateLocal,
- TySet `TyArrow` TyProp))
- (CApp
- (CGlobal HigherOrderPredicate)
- (CBound 0))
- higherOrderLocal <-
- checkedLocalPremise
- 1
- "higher-order local"
- higherOrderLocalProposition
-
- implicit <-
- planned
- fofFacts
- claim
- [higherOrderLocal, firstOrderLocal]
- []
- FirstOrderLocals
- ImplicitConstructionJustification
- assertEqual "implicit route" RouteFof
- (typedProblemRoute implicit)
- assertEqual "implicit FOF globals" [0]
- (typedBackendFactReference
- <$> toList
- (typedProblemGlobalPremises
- implicit))
- assertEqual "first-order local only" [0]
- (localPremiseOrdinalValue
- . typedLocalPremiseOrdinal
- <$> toList
- (typedProblemLocalPremises
- implicit))
-
- explicitFof <-
- planned
- fofFacts
- claim
- [higherOrderLocal, firstOrderLocal]
- []
- FirstOrderLocals
- ExplicitHigherOrderJustification
- assertEqual "explicit FOF route" RouteFof
- (typedProblemRoute explicitFof)
- assertEqual "explicit FOF references retain only FOF locals" [0]
- (localPremiseOrdinalValue
- . typedLocalPremiseOrdinal
- <$> toList
- (typedProblemLocalPremises explicitFof))
-
- explicitTh0 <-
- planned
- th0Facts
- claim
- [higherOrderLocal, firstOrderLocal]
- []
- CompleteLocals
- ExplicitHigherOrderJustification
- assertEqual "explicit TH0 route" RouteTh0
- (typedProblemRoute explicitTh0)
- assertEqual "explicit TH0 references retain complete locals" [0, 1]
- (localPremiseOrdinalValue
- . typedLocalPremiseOrdinal
- <$> toList
- (typedProblemLocalPremises explicitTh0))
-
- localOnly <-
- planned
- Vector.empty
- claim
- [higherOrderLocal, firstOrderLocal]
- []
- CompleteLocals
- ExplicitHigherOrderJustification
- assertEqual "local-only TH0 route" RouteTh0
- (typedProblemRoute localOnly)
- assertEqual "local order restored" [0, 1]
- (localPremiseOrdinalValue
- . typedLocalPremiseOrdinal
- <$> toList
- (typedProblemLocalPremises
- localOnly))
- assertEqual
- "complete ambient local inventory"
- (Map.fromList
- [ (ObjectLocal, TySet)
- , (PredicateLocal,
- TySet `TyArrow` TyProp)
- ])
- (typedProblemLocalTypes localOnly)
-
- case planTypedProblem
- testGlobalType
- Vector.empty
- claim
- [firstOrderLocal, firstOrderLocal]
- []
- CompleteLocals
- ExplicitHigherOrderJustification of
- Left
- (TypedProblemDuplicateLocalPremiseOrdinal
- duplicateOrdinal) ->
- assertEqual
- "duplicate local ordinal"
- 0
- (localPremiseOrdinalValue
- duplicateOrdinal)
- result ->
- assertFailure
- ("expected duplicate local ordinal error, got "
- <> showProblemResult result)
-
- higherOrderClaimProposition <-
- checkedProposition
- Vector.empty
- higherOrderClaim
- case planTypedProblem
- testGlobalType
- fofFacts
- higherOrderClaimProposition
- []
- []
- FirstOrderLocals
- ImplicitConstructionJustification of
- Left
- TypedProblemExplicitHigherOrderJustificationRequired{} ->
- pure ()
- result ->
- assertFailure
- ("expected explicit higher-order error, got "
- <> showProblemResult result)
- checkedFoundationValue <-
- either
- (assertFailure . show)
- pure
- Foundation.checkedFoundation
- case planTypedProblem
- testGlobalType
- fofFacts
- claim
- []
- [typedFoundationAuxiliaryInput
- checkedFoundationValue
- Foundation.SeparationCharacteristic]
- FirstOrderLocals
- ImplicitConstructionJustification of
- Left
- TypedProblemExplicitHigherOrderJustificationRequired{} ->
- pure ()
- result ->
- assertFailure
- ("expected implicit higher-order auxiliary error, got "
- <> showProblemResult result)
- unusedContext <-
- either
- (assertFailure . show)
- pure
- (checkScopedCanonicalCore
- testGlobalType
- [TySet `TyArrow` TyProp]
- firstOrderClaim)
- case supportedProposition
- (Vector.singleton
- (PredicateLocal,
- TySet `TyArrow` TyProp))
- unusedContext of
- Left (UnusedSupportedLocal PredicateLocal) ->
- pure ()
- Left err ->
- assertFailure
- ("unexpected exact-support error: "
- <> show err)
- Right _ ->
- assertFailure
- "unused ambient local entered exact support"
- where
- planned selectedFacts claim locals auxiliaries localPolicy higherOrderPolicy =
- either
- (assertFailure . show)
- pure
- (planTypedProblem
- testGlobalType
- selectedFacts
- claim
- locals
- auxiliaries
- localPolicy
- higherOrderPolicy)
-
- showProblemResult = \case
- Left err ->
- show err
- Right problem ->
- show (typedProblemRoute problem)
-
-admitsImplicitSetConstructions :: Assertion
-admitsImplicitSetConstructions = do
- checkedFoundationValue <-
- either
- (assertFailure . show)
- pure
- Foundation.checkedFoundation
- let separation =
- CApp
- (CApp
- (CIntrinsic Sep)
- (CIntrinsic Empty))
- (CLam TySet
- (CApp
- (CGlobal HigherOrderPredicate)
- (CLam TySet CFalsum)))
- separationClaim =
- CEq TySet separation separation
- filteredDomain =
- CApp
- (CApp
- (CIntrinsic Sep)
- (CBound 0))
- (CLam TySet
- (CEq TySet (CBound 0) (CBound 0)))
- innerReplacement =
- CApp
- (CApp (CIntrinsic Repl) filteredDomain)
- (CLam TySet (CBound 0))
- functionalReplacement =
- CApp
- (CIntrinsic FamilyUnion)
- (CApp
- (CApp
- (CIntrinsic Repl)
- (CIntrinsic Empty))
- (CLam TySet innerReplacement))
- replacementClaim =
- CEq TySet functionalReplacement functionalReplacement
- replacementTags =
- [ Foundation.FamilyUnionCharacteristic
- , Foundation.SeparationCharacteristic
- , Foundation.ReplacementCharacteristic
- ]
- auxiliary tag =
- typedFoundationAuxiliaryInput
- checkedFoundationValue tag
- plan selected claim locals tags =
- planTypedProblem
- testGlobalType
- selected
- claim
- locals
- (auxiliary <$> tags)
- FirstOrderLocals
- ImplicitConstructionJustification
-
- separationProposition <-
- checkedProposition Vector.empty separationClaim
- separationProblem <-
- either
- (assertFailure . show)
- pure
- (plan
- Vector.empty
- separationProposition
- []
- [Foundation.SeparationCharacteristic])
- assertEqual "separation implicit route" RouteTh0
- (typedProblemRoute separationProblem)
- assertEqual "separation characteristic only"
- [Foundation.SeparationCharacteristic]
- (typedProblemAuxiliaryTag
- <$> toList (typedProblemAuxiliaries separationProblem))
- assertEqual "separation selects no global premise"
- 0
- (Vector.length (typedProblemGlobalPremises separationProblem))
-
- replacementProposition <-
- checkedProposition Vector.empty replacementClaim
- replacementProblem <-
- either
- (assertFailure . show)
- pure
- (plan
- Vector.empty
- replacementProposition
- []
- replacementTags)
- assertEqual "functional replacement implicit route" RouteTh0
- (typedProblemRoute replacementProblem)
- assertEqual "functional replacement exact helper set"
- replacementTags
- (typedProblemAuxiliaryTag
- <$> toList (typedProblemAuxiliaries replacementProblem))
-
- firstOrderProposition <-
- checkedProposition Vector.empty firstOrderClaim
- firstOrderLocal <-
- checkedLocalPremise 0 "first-order" firstOrderProposition
- separationLocal <-
- checkedLocalPremise 2 "separation" separationProposition
- unrelatedLocalProposition <-
- checkedProposition
- (Vector.singleton
- (PredicateLocal, TySet `TyArrow` TyProp))
- (CApp
- (CGlobal HigherOrderPredicate)
- (CBound 0))
- unrelatedLocal <-
- checkedLocalPremise 1 "unrelated higher-order" unrelatedLocalProposition
- separationWithLocals <-
- either
- (assertFailure . show)
- pure
- (plan
- Vector.empty
- separationProposition
- [unrelatedLocal, firstOrderLocal]
- [Foundation.SeparationCharacteristic])
- assertEqual "inline separation keeps unrelated HO local out" RouteTh0
- (typedProblemRoute separationWithLocals)
- assertEqual "inline separation retains only FOF local" [0]
- ( localPremiseOrdinalValue
- . typedLocalPremiseOrdinal
- <$> toList (typedProblemLocalPremises separationWithLocals)
- )
- assertEqual "excluded HO local adds no auxiliary"
- [Foundation.SeparationCharacteristic]
- (typedProblemAuxiliaryTag
- <$> toList (typedProblemAuxiliaries separationWithLocals))
- localProblem <-
- either
- (assertFailure . show)
- pure
- (plan
- Vector.empty
- firstOrderProposition
- [unrelatedLocal, separationLocal, firstOrderLocal]
- [])
- assertEqual "implicit construction local remains excluded" RouteFof
- (typedProblemRoute localProblem)
- assertEqual "unrelated higher-order local remains unselected"
- [0]
- ( localPremiseOrdinalValue
- . typedLocalPremiseOrdinal
- <$> toList (typedProblemLocalPremises localProblem)
- )
-
- higherOrderFact <- checkedBackendFact (1 :: Int) higherOrderClaim
- expectImplicitHigherOrderRejection
- "implicit higher-order global remains forbidden"
- (plan
- (Vector.singleton higherOrderFact)
- separationProposition
- []
- [Foundation.SeparationCharacteristic])
-
- ordinaryHigherOrder <-
- checkedProposition Vector.empty
- (CEq TySet
- (CApp
- (CIntrinsic SetChoose)
- (CLam TySet CFalsum))
- (CIntrinsic Empty))
- expectImplicitHigherOrderRejection
- "ordinary implicit higher-order target remains forbidden"
- (plan Vector.empty ordinaryHigherOrder [] [])
- mixedHigherOrder <-
- checkedProposition Vector.empty
- (CImp
- separationClaim
- (supportedPropositionTerm ordinaryHigherOrder))
- expectImplicitHigherOrderRejection
- "construction does not admit another higher-order intrinsic"
- (plan
- Vector.empty
- mixedHigherOrder
- []
- [Foundation.SeparationCharacteristic])
-
- expectImplicitHigherOrderRejection
- "auxiliary tag alone grants no construction permission"
- (plan
- Vector.empty
- firstOrderProposition
- []
- [Foundation.SeparationCharacteristic])
- where
- expectImplicitHigherOrderRejection label = \case
- Left TypedProblemExplicitHigherOrderJustificationRequired{} ->
- pure ()
- Left err ->
- assertFailure (label <> ": unexpected error " <> show err)
- Right problem ->
- assertFailure
- (label <> ": unexpectedly routed "
- <> show (typedProblemRoute problem))
-
-rendersCheckedProblems :: Assertion
-rendersCheckedProblems = do
- fofFact <-
- checkedBackendFact
- (0 :: Int)
- firstOrderClaim
- th0Fact <-
- checkedBackendFact
- (1 :: Int)
- higherOrderClaim
- claim <-
- checkedProposition
- (Vector.singleton
- (ObjectLocal, TySet))
- (CApp
- (CGlobal FirstOrderPredicate)
- (CBound 0))
- fofProblem <-
- planned
- (Vector.singleton fofFact)
- claim
- FirstOrderLocals
- ImplicitConstructionJustification
- th0Problem <-
- planned
- (Vector.singleton th0Fact)
- claim
- CompleteLocals
- ExplicitHigherOrderJustification
- preparedFof <-
- either
- (assertFailure . show)
- pure
- (prepareTypedTptpProblem
- fofProblem)
- preparedTh0 <-
- either
- (assertFailure . show)
- pure
- (prepareTypedTptpProblem
- th0Problem)
- proverTask <-
- either
- (assertFailure . show)
- pure
- (prepareTypedProverTask
- DirectTask
- th0Problem)
- assertEqual "FOF route" RouteFof
- (preparedTypedTptpRoute preparedFof)
- assertBool "FOF formulas"
- ("fof(tg_h0,axiom,"
- `Text.isInfixOf`
- preparedTypedTptpText
- preparedFof)
- assertBool "FOF has no TH0 declarations"
- (not
- ("thf("
- `Text.isInfixOf`
- preparedTypedTptpText
- preparedFof))
- assertEqual "TH0 route" RouteTh0
- (preparedTypedTptpRoute preparedTh0)
- assertEqual "TH0 request dialect"
- VerificationTh0
- (preparedVerificationDialect
- (preparedTypedProverRequest
- proverTask))
- assertEqual "request preserves exact prepared text"
- (preparedTypedTptpText preparedTh0)
- (preparedVerificationText
- (preparedTypedProverRequest
- proverTask))
- for_
- [ "thf(tg_h0,axiom,"
- , "^ [V0:$i]"
- , "thf(tg_q0,conjecture,"
- ]
- \fragment ->
- assertBool
- ("TH0 contains " <> Text.unpack fragment)
- (fragment
- `Text.isInfixOf`
- preparedTypedTptpText
- preparedTh0)
- for_
- (Map.keys
- (preparedTypedTptpNameOrigins
- preparedTh0))
- \target ->
- assertBool
- ("valid generated name " <> Text.unpack target)
- (if "V" `Text.isPrefixOf` target
- then Tptp.isProperVariable target
- else Tptp.isProperAtomicWord target)
- where
- planned selectedFacts claim localPolicy higherOrderPolicy =
- either
- (assertFailure . show)
- pure
- (planTypedProblem
- testGlobalType
- selectedFacts
- claim
- []
- []
- localPolicy
- higherOrderPolicy)
-
-firstOrderClaim :: CanonicalTerm TestGlobal
-firstOrderClaim =
- CApp
- (CGlobal FirstOrderPredicate)
- (CIntrinsic Empty)
-
-higherOrderClaim :: CanonicalTerm TestGlobal
-higherOrderClaim =
- CApp
- (CGlobal HigherOrderPredicate)
- (CLam TySet
- (CApp
- (CGlobal FirstOrderPredicate)
- (CBound 0)))
-
-checkedProposition
- :: Vector (TestLocal, CoreType)
- -> CanonicalTerm TestGlobal
- -> IO
- (SupportedProposition
- TestLocal
- TestGlobal)
-checkedProposition support term = do
- checked <-
- either
- (assertFailure . show)
- pure
- (checkScopedCanonicalCore
- testGlobalType
- (snd <$> Vector.toList support)
- term)
- either
- (assertFailure . show)
- pure
- (supportedProposition support checked)
-
-checkedClosedProposition
- :: CanonicalTerm TestGlobal
- -> IO
- (SupportedProposition
- Void
- TestGlobal)
-checkedClosedProposition term = do
- checked <-
- either
- (assertFailure . show)
- pure
- (checkScopedCanonicalCore
- testGlobalType
- []
- term)
- either
- (assertFailure . show)
- pure
- (supportedProposition
- Vector.empty
- checked)
-
-checkedBackendFact
- :: ref
- -> CanonicalTerm TestGlobal
- -> IO (TypedBackendFact ref TestGlobal)
-checkedBackendFact reference term = do
- proposition <-
- checkedClosedProposition term
- capability <-
- either
- (assertFailure . show)
- pure
- (classifySupportedProposition
- testGlobalType
- proposition)
- pure
- (typedBackendFact
- reference
- proposition
- capability)
-
-checkedLocalPremise
- :: Natural
- -> Text
- -> SupportedProposition TestLocal TestGlobal
- -> IO
- (TypedLocalPremise
- TestLocal
- Text
- TestGlobal)
-checkedLocalPremise ordinal premiseOrigin proposition =
- either
- (assertFailure . show)
- pure
- (typedLocalPremise
- testGlobalType
- (localPremiseOrdinal ordinal)
- premiseOrigin
- proposition)
diff --git a/source/Test/Unit/CommandLine.hs b/source/Test/Unit/CommandLine.hs
deleted file mode 100644
index 110e00d..0000000
--- a/source/Test/Unit/CommandLine.hs
+++ /dev/null
@@ -1,799 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Unit.CommandLine (unitTests) where
-
-import Base
-import Felix.CommandLine
-import Felix.Output.Atomic qualified as Atomic
-import Felix.Source (safeRelativePath)
-import Felix.Store qualified as Store
-import Felix.Verification qualified as Verification
-import Felix.Provers qualified as Provers
-import Render.Html.Output qualified as HtmlOutput
-import Report.Location (pattern Nowhere)
-
-import Control.Exception (IOException, bracket)
-import Control.Exception qualified as Exception
-import Data.ByteString qualified as ByteString
-import Data.List qualified as List
-import Data.Text qualified as Text
-import Data.Text.Encoding qualified as TextEncoding
-import Options.Applicative (ParserResult(..))
-import Options.Applicative qualified as Options
-import System.Directory qualified as Directory
-import System.Environment (getEnvironment)
-import System.Exit (ExitCode(..))
-import System.FilePath.Posix ((</>))
-import System.Process
- ( CreateProcess(..)
- , proc
- , readCreateProcessWithExitCode
- )
-import Test.Tasty
-import Test.Tasty.HUnit
-
-unitTests :: TestTree
-unitTests =
- testGroup "Command line"
- [ testCase "parses the closed command model"
- parsesClosedCommands
- , testCase "rejects conflicting command options"
- rejectsConflictingOptions
- , testCase "maps structured outcomes to process status" do
- for_ outcomeCases \(outcome, expectedExitCode) ->
- commandOutcomeExitCode outcome
- `shouldBe` expectedExitCode
- , testCase "reports the committed HTML prefix"
- reportsCommittedHtmlPrefix
- , testCase "removes an unpublished dump temporary"
- removesFailedDumpTemporary
- , testGroup "process boundary"
- [ testCase "version needs no input or store"
- versionNeedsNoInputOrStore
- , testCase "parse-only uses no store or Vampire"
- parseOnlyUsesNoAuthority
- , testCase "malformed source has a stable failure class"
- malformedSourceHasStableFailure
- , testCase "invalid output needs no source pass or store startup"
- invalidOutputPrecedesStoreStartup
- , testCase "nested HTML routes fail before store startup"
- nestedHtmlRoutesPrecedeStoreStartup
- , testCase "verified theorem exits successfully" do
- (exitCode, stdout, stderr) <- runCliWithFakeVampire
- [ "printf '%s\\n' '% SZS status Theorem for cli'"
- , "exit 0"
- ]
- exitCode `shouldBe` ExitSuccess
- stdout `shouldBe` ""
- stderr `shouldContain` "Verification successful."
- , testCase "omitted proof reports a located explicit gap" do
- (exitCode, stdout, stderr) <-
- runCliWithSourceAndConfiguredVampire
- cliGapSource
- writeNonExecutableFile
- exitCode `shouldBe` ExitSuccess
- stdout `shouldBe` ""
- stderr `shouldContain`
- "Verification completed with explicit proof gaps."
- stderr `shouldContain` "1 explicit proof gap"
- stderr `shouldContain` "input.tex 5:5"
- , testCase "countermodel exits as verification rejection" do
- (exitCode, stdout, stderr) <- runCliWithFakeVampire
- [ "printf '%s\\n' '% SZS status CounterSatisfiable for cli'"
- , "exit 0"
- ]
- exitCode `shouldBe` ExitFailure 1
- stdout `shouldBe` ""
- stderr `shouldContain`
- "Verification failed: prover found countermodel"
- , testCase "failed prover exits as infrastructure failure" do
- (exitCode, stdout, stderr) <- runCliWithFakeVampire
- [ "printf '%s\\n' '% SZS status Theorem for cli'"
- , "exit 7"
- ]
- exitCode `shouldBe` ExitFailure 2
- stdout `shouldBe` ""
- stderr `shouldContain`
- "UnsuccessfulVampireExit (ExitFailure 7)"
- , testCase "prover launch failure exits as infrastructure failure" do
- (exitCode, stdout, stderr) <-
- runCliWithConfiguredVampire writeNonExecutableFile
- exitCode `shouldBe` ExitFailure 2
- stdout `shouldBe` ""
- stderr `shouldContain` "ProverLaunchFailed"
- , testCase "dumps the exact executed request once"
- dumpsExactExecutedRequest
- , testCase "launch failure dumps no request"
- launchFailureDumpsNoRequest
- , testCase "failed verification retains its executed dump subset"
- dumpsOnlyExecutedPrefix
- , testCase "dump and HTML share one verification"
- dumpAndHtmlVerifyOnce
- , testCase "semantic failure publishes no HTML"
- semanticFailurePublishesNoHtml
- , testCase "fresh and cached presentation publish equal HTML"
- freshAndCachedPresentationAgree
- , testCase "missing renderer data is a typed failure"
- missingRendererDataIsTyped
- , testCase
- "post-verification HTML failure retains authorization report"
- htmlFailureRetainsAuthorizationReport
- ]
- ]
-
-parsesClosedCommands :: Assertion
-parsesClosedCommands = do
- case parseCommandArguments ["--version"] of
- Success Version ->
- pure ()
- other ->
- assertFailure
- ("unexpected version parse: " <> showParserResult other)
- case parseCommandArguments ["input.tex", "--parseonly"] of
- Success (ParseOnly (Input "input.tex")) ->
- pure ()
- other ->
- assertFailure
- ("unexpected parse-only parse: " <> showParserResult other)
- case parseCommandArguments ["input.tex"] of
- Success
- (Verify
- (Input "input.tex")
- VerificationOptions
- { verificationStoreSelection =
- Store.DefaultStore
- }) ->
- pure ()
- other ->
- assertFailure
- ("unexpected default verify parse: "
- <> showParserResult other)
- case parseCommandArguments ["input.tex", "--jobs", "3"] of
- Success
- (Verify
- (Input "input.tex")
- VerificationOptions
- { verificationJobsOverride = Just jobs
- }) ->
- Provers.effectiveJobsValue jobs `shouldBe` 3
- other ->
- assertFailure
- ("unexpected jobs parse: " <> showParserResult other)
- case parseCommandArguments ["input.tex", "--fresh"] of
- Success
- (Verify
- (Input "input.tex")
- VerificationOptions
- { verificationStoreSelection =
- Store.FreshTemporaryStore
- }) ->
- pure ()
- other ->
- assertFailure
- ("unexpected verify parse: " <> showParserResult other)
-
-rejectsConflictingOptions :: Assertion
-rejectsConflictingOptions = do
- for_
- [ ["input.tex", "--parseonly", "--fresh"]
- , ["input.tex", "--parseonly", "--jobs", "2"]
- , ["input.tex", "--parseonly", "--dump", "dump"]
- , ["input.tex", "--parseonly", "--html"]
- , ["input.tex", "--store", "store.sqlite", "--fresh"]
- ]
- \arguments ->
- case parseCommandArguments arguments of
- Failure _failure ->
- pure ()
- other ->
- assertFailure
- ("conflicting options were accepted: "
- <> show arguments
- <> " as "
- <> showParserResult other)
- case parseCommandArguments ["input.tex", "--jobs", "0"] of
- Failure _failure -> pure ()
- other ->
- assertFailure
- ("non-positive jobs were accepted as "
- <> showParserResult other)
-
-showParserResult :: ParserResult Command -> String
-showParserResult = \case
- Success selected ->
- show selected
- Failure failure ->
- fst (Options.renderFailure failure "felix")
- CompletionInvoked _completion ->
- "completion invoked"
-
-versionNeedsNoInputOrStore :: Assertion
-versionNeedsNoInputOrStore =
- withCliFixture cliSource \fixture -> do
- (exitCode, stdout, stderr) <-
- runCliFixture fixture ["--version"]
- exitCode `shouldBe` ExitSuccess
- stdout `shouldContain` "Version 0.3.0.0"
- stderr `shouldBe` ""
- assertNoDefaultStore fixture
-
-parseOnlyUsesNoAuthority :: Assertion
-parseOnlyUsesNoAuthority =
- withCliFixture cliPreludeSyntaxSource \fixture -> do
- writeNonExecutableFile (cliFixtureVampire fixture)
- (exitCode, stdout, stderr) <-
- runCliFixture
- fixture
- ["input.tex", "--parseonly"]
- exitCode `shouldBe` ExitSuccess
- stdout `shouldBe` ""
- stderr `shouldBe` ""
- assertNoDefaultStore fixture
-
-malformedSourceHasStableFailure :: Assertion
-malformedSourceHasStableFailure =
- withCliFixture malformedCliSource \fixture -> do
- (exitCode, stdout, stderr) <-
- runCliFixture
- fixture
- ["input.tex", "--parseonly"]
- exitCode `shouldBe` ExitFailure 1
- stdout `shouldBe` ""
- stderr `shouldContain` "Parsing failed: project:input.tex"
- stderr `shouldContain` "input.tex 2:5"
- stderr `shouldContain` "unconsumed word"
- assertBool "does not print an internal error constructor"
- (not ("SourceParseError" `List.isInfixOf` stderr))
- assertNoDefaultStore fixture
-
-invalidOutputPrecedesStoreStartup :: Assertion
-invalidOutputPrecedesStoreStartup =
- withCliFixture cliSource \fixture -> do
- let dump = cliFixtureRoot fixture </> "dump"
- Directory.removeFile
- (cliFixtureRoot fixture </> "input.tex")
- Directory.createDirectory dump
- writeFile (dump </> "stale.p") "stale"
- (exitCode, stdout, stderr) <-
- runCliFixture fixture
- ["input.tex", "--dump", "dump"]
- exitCode `shouldBe` ExitFailure 2
- stdout `shouldBe` ""
- stderr `shouldContain` "Verification output preflight failed:"
- stderr `shouldContain` (Text.pack (show dump))
- stderr `shouldContain` "choose an absent or empty directory"
- stderr `shouldContain` "stale.p"
- assertNoDefaultStore fixture
-
-reportsCommittedHtmlPrefix :: Assertion
-reportsCommittedHtmlPrefix = do
- first <- checkedRelative "a.html"
- second <- checkedRelative "nested/b.html"
- failed <- checkedRelative "nested/c.html"
- assertEqual
- "deterministic committed prefix"
- [ "HTML publication failed at \"nested/c.html\": disk full"
- , "HTML files published before the failure: \"a.html\", \"nested/b.html\""
- ]
- (HtmlOutput.renderHtmlPublicationError
- (HtmlOutput.IncompleteHtmlPublication
- [first, second]
- failed
- "disk full"))
- where
- checkedRelative path =
- case safeRelativePath path of
- Left problem ->
- assertFailure
- ("invalid test route " <> show path <> ": " <> show problem)
- >> fail "unreachable"
- Right relative ->
- pure relative
-
-nestedHtmlRoutesPrecedeStoreStartup :: Assertion
-nestedHtmlRoutesPrecedeStoreStartup =
- withCliFixture nestedHtmlRootSource \fixture -> do
- let root = cliFixtureRoot fixture
- nested = root </> "a.html"
- Directory.createDirectory nested
- writeFile (root </> "a.tex") cliSource
- writeFile (nested </> "b.tex") cliSource
- (exitCode, stdout, stderr) <-
- runCliFixture fixture ["input.tex", "--html"]
- exitCode `shouldBe` ExitFailure 2
- stdout `shouldBe` ""
- stderr `shouldContain` "HTML route planning failed:"
- stderr `shouldContain` "\"a.html\""
- stderr `shouldContain` "\"a.html/b.html\""
- assertNoDefaultStore fixture
-
-removesFailedDumpTemporary :: Assertion
-removesFailedDumpTemporary =
- withTemporaryDirectory "felix-dump-atomic" \root -> do
- let destination = root </> "1.p"
- Directory.createDirectory destination
- result <- Exception.try
- (Atomic.writeBytesAtomically
- destination
- (TextEncoding.encodeUtf8 "complete request"))
- :: IO (Either IOException ())
- case result of
- Left _failure ->
- pure ()
- Right () ->
- assertFailure "dump publication unexpectedly succeeded"
- contents <- List.sort <$> Directory.listDirectory root
- assertEqual
- "only the pre-existing final target remains"
- ["1.p"]
- contents
-
-dumpsExactExecutedRequest :: Assertion
-dumpsExactExecutedRequest =
- withCliFixture cliSource \fixture -> do
- seedPackagedPreludeCache fixture
- let captured = cliFixtureRoot fixture </> "captured.p"
- writeExecutableScript
- (cliFixtureVampire fixture)
- [ "cat > " <> show captured
- , "printf '%s\\n' '% SZS status Theorem for cli'"
- ]
- (exitCode, _stdout, stderr) <-
- runCliFixture fixture
- [ "input.tex"
- , "--dump"
- , "dump"
- ]
- exitCode `shouldBe` ExitSuccess
- stderr `shouldContain` "Verification successful."
- dumped <- ByteString.readFile
- (cliFixtureRoot fixture </> "dump" </> "1-1.p")
- sent <- ByteString.readFile captured
- assertEqual "dump is the exact process input" sent dumped
- assertBool "request is dumped only once"
- . not
- =<< Directory.doesPathExist
- (cliFixtureRoot fixture </> "dump" </> "1-2.p")
-
-launchFailureDumpsNoRequest :: Assertion
-launchFailureDumpsNoRequest =
- withCliFixture cliSource \fixture -> do
- seedPackagedPreludeCache fixture
- writeNonExecutableFile (cliFixtureVampire fixture)
- (exitCode, _stdout, stderr) <-
- runCliFixture fixture
- [ "input.tex"
- , "--dump"
- , "dump"
- ]
- exitCode `shouldBe` ExitFailure 2
- stderr `shouldContain` "ProverLaunchFailed"
- assertBool "no request was dumped before process launch"
- . not
- =<< Directory.doesPathExist
- (cliFixtureRoot fixture </> "dump" </> "1-1.p")
-
-dumpsOnlyExecutedPrefix :: Assertion
-dumpsOnlyExecutedPrefix =
- withCliFixture cliTwoSource \fixture -> do
- seedPackagedPreludeCache fixture
- writeExecutableScript
- (cliFixtureVampire fixture)
- [ "cat >/dev/null"
- , "printf '%s\\n' '% SZS status CounterSatisfiable for cli'"
- ]
- (exitCode, _stdout, stderr) <-
- runCliFixture fixture
- [ "input.tex"
- , "--dump"
- , "dump"
- ]
- exitCode `shouldBe` ExitFailure 1
- stderr `shouldContain` "prover found countermodel"
- assertBool "executed request was dumped"
- =<< Directory.doesFileExist
- (cliFixtureRoot fixture </> "dump" </> "1-1.p")
- -- Prospective execution may start a source-later request before the
- -- admission cursor observes this first rejection. Dump ownership is
- -- therefore the actual executed subset, not a semantic prefix.
-
-dumpAndHtmlVerifyOnce :: Assertion
-dumpAndHtmlVerifyOnce =
- withCliFixture cliSource \fixture -> do
- seedPackagedPreludeCache fixture
- let countPath = cliFixtureRoot fixture </> "vampire-runs"
- writeExecutableScript
- (cliFixtureVampire fixture)
- [ "cat >/dev/null"
- , "printf '%s\\n' run >> " <> show countPath
- , "printf '%s\\n' '% SZS status Theorem for cli'"
- ]
- (exitCode, _stdout, stderr) <-
- runCliFixture fixture
- [ "input.tex"
- , "--dump"
- , "dump"
- , "--html"
- ]
- exitCode `shouldBe` ExitSuccess
- stderr `shouldContain` "Verification successful."
- runs <- List.lines <$> readFile countPath
- assertEqual "one semantic verification" ["run"] runs
- assertBool "request dump was published"
- =<< Directory.doesFileExist
- (cliFixtureRoot fixture </> "dump" </> "1-1.p")
- assertBool "root HTML page was published"
- =<< Directory.doesFileExist
- (cliFixtureRoot fixture </> "html" </> "input.html")
- assertBool "HTML support asset was published"
- =<< Directory.doesFileExist
- (cliFixtureRoot fixture
- </> "html"
- </> "_static"
- </> "naproche-html.js")
-
-semanticFailurePublishesNoHtml :: Assertion
-semanticFailurePublishesNoHtml =
- withCliFixture cliSource \fixture -> do
- seedPackagedPreludeCache fixture
- writeExecutableScript
- (cliFixtureVampire fixture)
- [ "cat >/dev/null"
- , "printf '%s\\n' '% SZS status CounterSatisfiable for cli'"
- ]
- (exitCode, _stdout, stderr) <-
- runCliFixture fixture
- [ "input.tex"
- , "--dump"
- , "dump"
- , "--html"
- ]
- exitCode `shouldBe` ExitFailure 1
- stderr `shouldContain` "prover found countermodel"
- assertBool "semantic failure retains the executed request dump"
- =<< Directory.doesFileExist
- (cliFixtureRoot fixture </> "dump" </> "1-1.p")
- assertBool "semantic failure publishes no HTML"
- . not
- =<< Directory.doesPathExist
- (cliFixtureRoot fixture </> "html")
-
-freshAndCachedPresentationAgree :: Assertion
-freshAndCachedPresentationAgree =
- withCliFixture cliSource \fixture -> do
- seedPackagedPreludeCache fixture
- writeExecutableScript
- (cliFixtureVampire fixture)
- [ "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for cli'"
- ]
- (freshExit, _freshStdout, freshStderr) <-
- runCliFixture fixture ["input.tex", "--html"]
- freshExit `shouldBe` ExitSuccess
- freshStderr `shouldContain` "Verification successful."
- let htmlRoot = cliFixtureRoot fixture </> "html"
- page = htmlRoot </> "input.html"
- support =
- htmlRoot </> "_static" </> "naproche-html.js"
- freshPage <- ByteString.readFile page
- freshSupport <- ByteString.readFile support
- Directory.removePathForcibly htmlRoot
- writeNonExecutableFile (cliFixtureVampire fixture)
- (warmExit, _warmStdout, warmStderr) <-
- runCliFixture fixture ["input.tex", "--html"]
- warmExit `shouldBe` ExitSuccess
- warmStderr `shouldContain` "Verification successful."
- warmPage <- ByteString.readFile page
- warmSupport <- ByteString.readFile support
- assertEqual "fresh/cache-hit page bytes" freshPage warmPage
- assertEqual "fresh/cache-hit support bytes"
- freshSupport warmSupport
-
-missingRendererDataIsTyped :: Assertion
-missingRendererDataIsTyped =
- withCliFixture cliSource \fixture -> do
- seedPackagedPreludeCache fixture
- Directory.removeFile
- (cliFixtureRoot fixture </> "library" </> "lexicon.tsv")
- writeExecutableScript
- (cliFixtureVampire fixture)
- [ "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for cli'"
- ]
- (exitCode, stdout, stderr) <-
- runCliFixture fixture ["input.tex", "--html"]
- exitCode `shouldBe` ExitFailure 2
- stdout `shouldBe` ""
- stderr `shouldContain` "HTML preparation failed:"
- stderr `shouldContain` "renderer data \"lexicon.tsv\" was not found"
- assertBool "does not expose an ErrorCall"
- (not ("ErrorCall" `List.isInfixOf` stderr))
- assertBool "failed preparation publishes no HTML"
- . not
- =<< Directory.doesPathExist
- (cliFixtureRoot fixture </> "html")
-
-htmlFailureRetainsAuthorizationReport :: Assertion
-htmlFailureRetainsAuthorizationReport =
- withCliFixture cliGapSource \fixture -> do
- seedPackagedPreludeCache fixture
- Directory.removeFile
- (cliFixtureRoot fixture </> "library" </> "lexicon.tsv")
- writeNonExecutableFile (cliFixtureVampire fixture)
- (exitCode, stdout, stderr) <-
- runCliFixture fixture ["input.tex", "--html"]
- exitCode `shouldBe` ExitFailure 2
- stdout `shouldBe` ""
- stderr `shouldContain`
- "Verification succeeded, but HTML preparation failed:"
- stderr `shouldContain`
- "Direct source authorization summary: 0 source axioms, 1 explicit proof gap."
- stderr `shouldContain` "Explicit proof gap at input.tex 5:5"
- assertBool "failed output publishes no HTML"
- . not
- =<< Directory.doesPathExist
- (cliFixtureRoot fixture </> "html")
-
-outcomeCases :: [(CommandOutcome, ExitCode)]
-outcomeCases =
- [ (CommandCompleted, ExitSuccess)
- , (VerificationSucceeded emptyReport emptySlowReport, ExitSuccess)
- , (VerificationCompletedWithGaps emptyReport emptySlowReport, ExitSuccess)
- , ( VerificationRejected
- emptyReport
- (Verification.FailedVerification
- Nowhere
- (Verification.CountermodelFailure ""))
- emptySlowReport
- , ExitFailure 1
- )
- , ( VerificationRejected
- emptyReport
- (Verification.FailedVerification
- Nowhere
- (Verification.IndeterminateFailure ""))
- emptySlowReport
- , ExitFailure 2
- )
- , ( VerificationCheckingRejected
- emptyReport
- (Verification.VerificationModuleSchedulerInvariant "test")
- emptySlowReport
- , ExitFailure 2
- )
- ]
-
-emptyReport :: Verification.VerificationReport
-emptyReport =
- Verification.VerificationReport
- { Verification.verificationDirectEscapes = []
- }
-
-emptySlowReport :: Provers.SlowAtpReport
-emptySlowReport = Provers.SlowAtpReport 0 []
-
-runCliWithFakeVampire
- :: [String]
- -> IO (ExitCode, String, String)
-runCliWithFakeVampire scriptLines =
- runCliWithConfiguredVampire \vampirePath -> do
- writeExecutableScript vampirePath
- (["cat >/dev/null"] <> scriptLines)
-
-runCliWithConfiguredVampire
- :: (FilePath -> IO ())
- -> IO (ExitCode, String, String)
-runCliWithConfiguredVampire =
- runCliWithSourceAndConfiguredVampire cliSource
-
-runCliWithSourceAndConfiguredVampire
- :: String
- -> (FilePath -> IO ())
- -> IO (ExitCode, String, String)
-runCliWithSourceAndConfiguredVampire source prepareVampire =
- withCliFixture source \fixture -> do
- seedPackagedPreludeCache fixture
- prepareVampire (cliFixtureVampire fixture)
- runCliFixture fixture ["input.tex"]
-
-data CliFixture = CliFixture
- { cliFixtureRoot :: !FilePath
- , cliFixtureExecutable :: !FilePath
- , cliFixtureVampire :: !FilePath
- , cliFixtureCacheRoot :: !FilePath
- , cliFixtureEnvironment :: ![(String, String)]
- }
-
-withCliFixture
- :: String
- -> (CliFixture -> IO value)
- -> IO value
-withCliFixture source action =
- withTemporaryDirectory "felix-cli" \temp -> do
- felixExecutable <- requireFelixExecutable
- repositoryRoot <- Directory.getCurrentDirectory
- let sourcePath = temp </> "input.tex"
- vampirePath = temp </> "vampire"
- libraryPath = temp </> "library"
- debugPath = temp </> "debug"
- cacheRoot = temp </> "cache"
- Directory.createDirectory libraryPath
- Directory.createDirectory debugPath
- Directory.createDirectory cacheRoot
- writeFile sourcePath source
- ByteString.readFile
- (repositoryRoot </> "library" </> "lexicon.tsv")
- >>= ByteString.writeFile
- (libraryPath </> "lexicon.tsv")
- inheritedEnvironment <- getEnvironment
- let processEnvironment =
- setEnvironmentVariable
- "XDG_CACHE_HOME"
- cacheRoot
- (setEnvironmentVariable
- "FELIX_VAMPIRE"
- vampirePath
- (setEnvironmentVariable
- "NAPROCHE_LIB"
- libraryPath
- inheritedEnvironment))
- action
- CliFixture
- { cliFixtureRoot = temp
- , cliFixtureExecutable = felixExecutable
- , cliFixtureVampire = vampirePath
- , cliFixtureCacheRoot = cacheRoot
- , cliFixtureEnvironment = processEnvironment
- }
-
-runCliFixture
- :: CliFixture
- -> [String]
- -> IO (ExitCode, String, String)
-runCliFixture fixture arguments =
- readCreateProcessWithExitCode
- ((proc
- (cliFixtureExecutable fixture)
- arguments)
- { cwd = Just (cliFixtureRoot fixture)
- , env = Just (cliFixtureEnvironment fixture)
- })
- ""
-
--- | Populate only the packaged final-prelude root. Process-boundary tests
--- can then exercise the requested ordinary module outcome without making
--- their fake prover depend on the prelude's private obligation count.
-seedPackagedPreludeCache :: CliFixture -> Assertion
-seedPackagedPreludeCache fixture = do
- let sourcePath = cliFixtureRoot fixture </> "input.tex"
- original <- ByteString.readFile sourcePath
- writeExecutableScript
- (cliFixtureVampire fixture)
- [ "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for prelude seed'"
- ]
- (exitCode, stdout, stderr) <-
- (do
- writeFile sourcePath "% cache the packaged final prelude\n"
- runCliFixture fixture ["input.tex"])
- `Exception.finally` ByteString.writeFile sourcePath original
- exitCode `shouldBe` ExitSuccess
- stdout `shouldBe` ""
- stderr `shouldContain` "Verification successful."
-
-assertNoDefaultStore :: CliFixture -> Assertion
-assertNoDefaultStore fixture =
- assertBool "default store was not created"
- . not
- =<< Directory.doesPathExist
- (cliFixtureCacheRoot fixture </> "felix")
-
-writeExecutableScript :: FilePath -> [String] -> IO ()
-writeExecutableScript path scriptLines = do
- writeFile path
- (unlines (["#!/bin/sh"] <> scriptLines))
- permissions <- Directory.getPermissions path
- Directory.setPermissions path
- (Directory.setOwnerExecutable True permissions)
-
-writeNonExecutableFile :: FilePath -> IO ()
-writeNonExecutableFile path = do
- exists <- Directory.doesPathExist path
- if exists
- then Directory.removeFile path
- else pure ()
- writeFile path "not executable"
-
-requireFelixExecutable :: IO FilePath
-requireFelixExecutable :: IO FilePath
- = do
- executable <- Directory.findExecutable "felix"
- case executable of
- Just path ->
- pure path
- Nothing -> do
- assertFailure "felix build tool is not available on PATH"
- pure "felix"
-
-setEnvironmentVariable
- :: String
- -> String
- -> [(String, String)]
- -> [(String, String)]
-setEnvironmentVariable name value environment =
- (name, value) : List.filter ((/= name) . fst) environment
-
-cliSource :: String
-cliSource =
- unlines
- [ "\\begin{proposition}\\label{cli_test}"
- , " $\\forall x. x = x$."
- , "\\end{proposition}"
- ]
-
-cliPreludeSyntaxSource :: String
-cliPreludeSyntaxSource =
- unlines
- [ "\\begin{proposition}\\label{parse_prelude_syntax}"
- , " For all $x$ we have $\\preludeSuccessor{x} = \\preludeSuccessor{x}$."
- , "\\end{proposition}"
- ]
-
-cliGapSource :: String
-cliGapSource =
- unlines
- [ "\\begin{proposition}\\label{cli_gap}"
- , " $\\forall x. x = x$."
- , "\\end{proposition}"
- , "\\begin{proof}"
- , " Omitted."
- , "\\end{proof}"
- ]
-
-cliTwoSource :: String
-cliTwoSource =
- unlines
- [ "\\begin{proposition}\\label{cli_first}"
- , " $\\forall x. x = x$."
- , "\\end{proposition}"
- , "\\begin{proposition}\\label{cli_second}"
- , " $\\forall y. y = y$."
- , "\\end{proposition}"
- ]
-
-malformedCliSource :: String
-malformedCliSource =
- unlines
- [ "\\begin{proposition}\\label{malformed}"
- , " This is not a proposition."
- , "\\end{proposition}"
- ]
-
-nestedHtmlRootSource :: String
-nestedHtmlRootSource =
- unlines
- [ "\\import{a.tex}"
- , "\\import{a.html/b.tex}"
- ]
-
-withTemporaryDirectory :: String -> (FilePath -> IO a) -> IO a
-withTemporaryDirectory template =
- bracket create Directory.removePathForcibly
- where
- create = do
- systemTemp <- Directory.getTemporaryDirectory
- (path, handle) <- openTempFile systemTemp template
- hClose handle
- Directory.removeFile path
- Directory.createDirectory path
- pure path
-
-shouldContain :: String -> Text -> Assertion
-shouldContain actual expected =
- assertBool
- ("expected " <> show actual <> " to contain " <> show expected)
- (expected `Text.isInfixOf` Text.pack actual)
-
-shouldBe :: (Eq a, Show a, HasCallStack) => a -> a -> Assertion
-shouldBe =
- flip (assertEqual "")
diff --git a/source/Test/Unit/Concrete.hs b/source/Test/Unit/Concrete.hs
deleted file mode 100644
index 7776552..0000000
--- a/source/Test/Unit/Concrete.hs
+++ /dev/null
@@ -1,221 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Unit.Concrete (unitTests) where
-
-import Base
-import Report.Location
-import Syntax.Abstract qualified as Raw
-import Syntax.Concrete (grammar)
-import Syntax.Lexicon (builtins)
-import Syntax.Token (runLexer)
-
-import Data.Text qualified as Text
-import Test.Tasty
-import Test.Tasty.HUnit
-import Text.Earley (fullParses, parser)
-import Text.Megaparsec (errorBundlePretty)
-
-unitTests :: TestTree
-unitTests =
- testGroup "Parser"
- [ testCase
- "textual connectives follow symbolic precedence"
- textualConnectivePrecedence
- , testCase
- "transfinite induction precedes its continuation"
- transfiniteInductionContinuation
- ]
-
-data StatementShape
- = Truth
- | Falsity
- | Connected Raw.Connective StatementShape StatementShape
- | Scoped StatementShape
- deriving (Show, Eq)
-
-textualConnectivePrecedence :: Assertion
-textualConnectivePrecedence = do
- for_ cases \(label, statement, expected) ->
- assertEqual label (Right expected) (statementShape =<< parseStatement statement)
-
- assertBool
- "chained iff is rejected"
- (case parseStatement "$\\top$ iff $\\bot$ iff $\\top$" of
- Left _ -> True
- Right _ -> False)
-
- assertEqual
- "textual and symbolic connective trees agree"
- (statementShape
- =<< parseStatement
- "$\\top \\land \\bot \\lor \\top$")
- (statementShape
- =<< parseStatement
- "$\\top$ and $\\bot$ or $\\top$")
- where
- cases =
- [ ( "and binds tighter than following or"
- , "$\\top$ and $\\bot$ or $\\top$"
- , Connected Raw.Disjunction
- (Connected Raw.Conjunction Truth Falsity)
- Truth
- )
- , ( "and binds tighter than preceding or"
- , "$\\top$ or $\\bot$ and $\\top$"
- , Connected Raw.Disjunction
- Truth
- (Connected Raw.Conjunction Falsity Truth)
- )
- , ( "and associates left"
- , "$\\top$ and $\\bot$ and $\\top$"
- , Connected Raw.Conjunction
- (Connected Raw.Conjunction Truth Falsity)
- Truth
- )
- , ( "or associates left"
- , "$\\top$ or $\\bot$ or $\\top$"
- , Connected Raw.Disjunction
- (Connected Raw.Disjunction Truth Falsity)
- Truth
- )
- , ( "either is accepted after ordinary or"
- , "$\\top$ or either $\\bot$ or $\\top$"
- , Connected Raw.Disjunction
- Truth
- (Connected Raw.ExclusiveOr Falsity Truth)
- )
- , ( "implication associates right"
- , "if $\\top$ then if $\\bot$ then $\\top$"
- , Connected Raw.Implication
- Truth
- (Connected Raw.Implication Falsity Truth)
- )
- , ( "a quantified implication antecedent ends at then"
- , "if for all $x$ we have $\\top$ then $\\bot$"
- , Connected Raw.Implication
- (Scoped Truth)
- Falsity
- )
- , ( "parentheses override precedence"
- , "($\\top$ or $\\bot$) and $\\top$"
- , Connected Raw.Conjunction
- (Connected Raw.Disjunction Truth Falsity)
- Truth
- )
- , ( "a quantified right operand scopes over its continuation"
- , "$\\top$ iff there exists $x$ such that $\\bot$ and $\\top$"
- , Connected Raw.Equivalence
- Truth
- (Scoped
- (Connected Raw.Conjunction Falsity Truth))
- )
- ]
-
-parseStatement :: Text -> Either String Raw.Stmt
-parseStatement statement = do
- chunks <- case runLexer
- (FileId 46)
- "textual-connectives.tex"
- (Text.unlines
- [ "\\begin{axiom}\\label{textual_connectives}"
- , statement <> "."
- , "\\end{axiom}"
- ]) of
- Left err ->
- Left (errorBundlePretty err)
- Right (_imports, chunks') ->
- Right chunks'
- tokens <- case chunks of
- [tokens'] ->
- Right tokens'
- _ ->
- Left ("expected one source chunk, got " <> show (length chunks))
- case fullParses (parser (grammar builtins)) tokens of
- ( [Raw.BlockAxiom
- _location
- _title
- _marker
- (Raw.Axiom [] statement')]
- , _report
- ) ->
- Right statement'
- (blocks, report) ->
- Left
- ( "expected one axiom, got "
- <> show blocks
- <> " with "
- <> show report
- )
-
-statementShape :: Raw.Stmt -> Either String StatementShape
-statementShape = \case
- Raw.StmtConnected conn _ left right ->
- Connected conn
- <$> statementShape left
- <*> statementShape right
- Raw.StmtFormula formula ->
- formulaShape formula
- Raw.SymbolicQuantified _ _ _ _ _ statement ->
- Scoped <$> statementShape statement
- statement ->
- Left ("unsupported statement in precedence test: " <> show statement)
-
-formulaShape :: Raw.Formula -> Either String StatementShape
-formulaShape = \case
- Raw.PropositionalConstant _ Raw.IsTop ->
- Right Truth
- Raw.PropositionalConstant _ Raw.IsBottom ->
- Right Falsity
- Raw.Connected _ conn left right ->
- Connected conn
- <$> formulaShape left
- <*> formulaShape right
- formula ->
- Left ("unsupported formula in precedence test: " <> show formula)
-
-transfiniteInductionContinuation :: Assertion
-transfiniteInductionContinuation =
- case runLexer
- (FileId 45)
- "transfinite-induction.tex"
- sourceText of
- Left err ->
- assertFailure (errorBundlePretty err)
- Right (_imports, [tokens]) ->
- case fullParses (parser (grammar builtins)) tokens of
- ( [ Raw.BlockProof
- _start
- (Raw.ByOrdInduction methodLocation
- (Raw.Qed
- (Just continuationLocation)
- Raw.JustificationEmpty))
- _end
- ]
- , _report
- ) -> do
- assertEqual
- "method header line"
- 2
- (locLine methodLocation)
- assertEqual
- "continuation line"
- 3
- (locLine continuationLocation)
- (blocks, report) ->
- assertFailure
- ( "expected one transfinite-induction proof, got "
- <> show blocks
- <> " with "
- <> show report
- )
- Right (_imports, chunks) ->
- assertFailure
- ("expected one proof chunk, got " <> show (length chunks))
- where
- sourceText =
- Text.unlines
- [ "\\begin{proof}"
- , "[proof by transfinite induction]"
- , "Trivial."
- , "\\end{proof}"
- ]
diff --git a/source/Test/Unit/Core.hs b/source/Test/Unit/Core.hs
deleted file mode 100644
index 643dc38..0000000
--- a/source/Test/Unit/Core.hs
+++ /dev/null
@@ -1,670 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module Test.Unit.Core (unitTests) where
-
-import Base hiding (Empty)
-import Checking.Core
-import Checking.Foundation qualified as Foundation
-import Checking.SetConstruction
-
-import Control.DeepSeq (NFData(..), force)
-import Hedgehog
-import Hedgehog.Gen qualified as Gen
-import Hedgehog.Range qualified as Range
-import Data.Set qualified as Set
-import Test.Tasty
-import Test.Tasty.HUnit hiding (assert)
-import Test.Tasty.Hedgehog (testPropertyNamed)
-
-
-data TestGlobal
- = TestGlobal
- | TestPairGlobal
- deriving (Show, Eq, Ord)
-
-instance NFData TestGlobal where
- rnf _global =
- ()
-
-testGlobalType :: TestGlobal -> Maybe CoreType
-testGlobalType TestGlobal =
- Just TySet
-testGlobalType TestPairGlobal =
- Just (TySet `TyArrow` (TySet `TyArrow` TySet))
-
-unitTests :: TestTree
-unitTests =
- testGroup "Checked core"
- [ testCase
- "freezes explicit binder positions"
- freezesExplicitBinderPositions
- , testCase
- "freezes generalized substitution without capture"
- freezesGeneralizedSubstitution
- , testCase
- "rejects ill-typed and open terms"
- rejectsInvalidTerms
- , testCase
- "rechecks canonical terms without unchecked construction"
- rechecksCanonicalTerms
- , testCase
- "checks scoped canonical weakening and substitution"
- checksScopedCanonicalOperations
- , testCase
- "builds set-induction hypotheses from the complete property"
- buildsSetInductionHypotheses
- , testCase
- "specializes the checked separation characteristic"
- specializesCheckedSeparationCharacteristic
- , testCase
- "specializes the checked replacement characteristic"
- specializesCheckedReplacementCharacteristic
- , testCase
- "derives named construction views from checked components"
- derivesNamedConstructionViews
- , testCase
- "thaws checked closed terms without changing them"
- thawsCheckedClosedTerms
- , testPropertyNamed
- "optimized freeze agrees with bounded reference"
- "prop_freezeAgreesWithReference"
- prop_freezeAgreesWithReference
- ]
-
-freezesExplicitBinderPositions :: Assertion
-freezesExplicitBinderPositions = do
- let x = 0 :: Int
- y = 1 :: Int
- freeze body = do
- checked <-
- either
- (assertFailure . show)
- pure
- (checkClosedCore
- testGlobalType
- (coreLambda TySet x
- (coreLambda TyProp y body)))
- either
- (assertFailure . show)
- (pure . frozenCoreTerm)
- (freezeClosed checked)
- nearest <-
- freeze (coreLocal y)
- outer <-
- freeze (coreLocal x)
- global <-
- freeze (coreGlobal TestGlobal)
- assertEqual
- "nearest binder"
- (CLam TySet (CLam TyProp (CBound 0)))
- nearest
- assertEqual
- "outer binder"
- (CLam TySet (CLam TyProp (CBound 1)))
- outer
- assertEqual
- "global with both vacuous binders"
- (CLam TySet (CLam TyProp (CGlobal TestGlobal)))
- global
-
-freezesGeneralizedSubstitution :: Assertion
-freezesGeneralizedSubstitution = do
- let outer = 0 :: Int
- inner = 1 :: Int
- placeholder = 2 :: Int
- innerTerm =
- coreLambda TySet inner (coreLocal placeholder)
- substituted =
- innerTerm >>= \local ->
- if local == placeholder
- then coreLocal outer
- else coreLocal local
- term =
- coreLambda TyProp outer substituted
- checked <-
- either
- (assertFailure . show)
- pure
- (checkClosedCore testGlobalType term)
- optimized <-
- either
- (assertFailure . show)
- pure
- (freezeClosed checked)
- reference <-
- either
- (assertFailure . show)
- pure
- (referenceFreezeClosed checked)
- assertEqual "reference result" reference optimized
- assertEqual
- "outer variable remains outside the inner binder"
- (CLam TyProp (CLam TySet (CBound 1)))
- (frozenCoreTerm optimized)
-
-rejectsInvalidTerms :: Assertion
-rejectsInvalidTerms = do
- assertEqual
- "free local"
- (Left UnboundCoreLocal)
- (checkedCoreType
- <$> checkClosedCore
- testGlobalType
- (coreLocal (0 :: Int)))
- assertEqual
- "application argument"
- (Left
- (ApplicationArgumentTypeMismatch
- TySet
- TyProp))
- (checkedCoreType
- <$> checkClosedCore
- testGlobalType
- (coreApply
- (coreIntrinsic FamilyUnion)
- coreFalsum))
- assertEqual
- "equality operand"
- (Left
- (EqualityOperandTypeMismatch
- TySet
- TyProp))
- (checkedCoreType
- <$> checkClosedCore
- testGlobalType
- (coreEquality
- TySet
- coreFalsum
- (coreGlobal TestGlobal)))
-
-rechecksCanonicalTerms :: Assertion
-rechecksCanonicalTerms = do
- let term =
- CForall TySet
- (CEq TySet
- (CBound 0)
- (CBound 0))
- assertEqual
- "well-typed canonical proposition"
- (Right (TyProp, term))
- ( (\checked ->
- ( frozenCoreType checked
- , frozenCoreTerm checked
- ))
- <$> checkCanonicalCore testGlobalType term
- )
- assertEqual
- "out-of-scope de Bruijn index"
- (Left (UnboundCoreIndex 1))
- (frozenCoreType
- <$> checkCanonicalCore
- testGlobalType
- (CForall TySet (CBound 1)))
- assertEqual
- "canonical application still checks argument types"
- (Left
- (ApplicationArgumentTypeMismatch
- TySet
- TyProp))
- (frozenCoreType
- <$> checkCanonicalCore
- testGlobalType
- (CApp
- (CIntrinsic FamilyUnion)
- CFalsum))
-
-checksScopedCanonicalOperations :: Assertion
-checksScopedCanonicalOperations = do
- scoped <-
- either
- (assertFailure . show)
- pure
- (checkScopedCanonicalCore
- testGlobalType
- [TySet]
- (CBound 0))
- weakened <-
- either
- (assertFailure . show)
- pure
- (weakenScopedCore
- testGlobalType
- TyProp
- scoped)
- assertEqual
- "nearest binder insertion shifts the prior local"
- ( [TyProp, TySet]
- , TySet
- , CBound 1
- )
- ( scopedCoreContext weakened
- , scopedCoreType weakened
- , scopedCoreTerm weakened
- )
- assertEqual
- "top-level binder substitution removes its index"
- (CEq TySet
- (CIntrinsic Empty)
- (CIntrinsic Empty))
- (instantiateCanonical
- (CIntrinsic Empty
- :: CanonicalTerm TestGlobal)
- (CEq TySet
- (CBound 0)
- (CBound 0)))
- root <-
- either
- (assertFailure . show)
- pure
- (checkScopedCanonicalCore
- testGlobalType
- []
- (CGlobal TestGlobal))
- assertEqual
- "empty scoped context closes"
- (Just
- (TySet, CGlobal TestGlobal))
- ( (\closed ->
- ( frozenCoreType closed
- , frozenCoreTerm closed
- ))
- <$> closeScopedCore root
- )
-
-buildsSetInductionHypotheses :: Assertion
-buildsSetInductionHypotheses = do
- let propertyTerm =
- CImp
- (CEq TySet
- (CBound 0)
- (CIntrinsic Empty))
- (CEq TySet
- (CBound 0)
- (CBound 0))
- claimProperty <-
- either
- (assertFailure . show)
- pure
- (checkScopedCanonicalCore
- testGlobalType
- [TySet]
- propertyTerm)
- (predicate, hypothesis, step, result) <-
- maybe
- (assertFailure "set-induction instance was not constructed")
- pure
- (scopedSetInductionInstance 0 claimProperty)
- let abstractedProperty =
- CImp
- (CEq TySet
- (CBound 0)
- (CIntrinsic Empty))
- (CEq TySet
- (CBound 0)
- (CBound 0))
- memberHypothesis =
- CForall TySet
- (CImp
- (CApp
- (CApp
- (CIntrinsic Member)
- (CBound 0))
- (CBound 1))
- abstractedProperty)
- assertEqual
- "set induction abstracts the selected property once"
- (CLam TySet abstractedProperty)
- (scopedCoreTerm predicate)
- assertEqual
- "antecedent and goal are both generalized over the member"
- memberHypothesis
- (scopedCoreTerm hypothesis)
- assertEqual
- "set-induction step owns its member-wise hypothesis"
- (CForall TySet
- (CImp memberHypothesis abstractedProperty))
- (scopedCoreTerm step)
- assertEqual
- "set-induction result closes the complete property"
- (CForall TySet abstractedProperty)
- (scopedCoreTerm result)
-
-specializesCheckedSeparationCharacteristic :: Assertion
-specializesCheckedSeparationCharacteristic = do
- foundation <-
- either
- (assertFailure . show)
- pure
- Foundation.checkedFoundation
- let bound = CIntrinsic Empty
- predicate =
- CLam TySet
- (CEq TySet (CBound 0) (CBound 0))
- separation =
- CApp
- (CApp (CIntrinsic Sep) bound)
- predicate
- body <-
- either
- (assertFailure . show)
- pure
- (checkScopedCanonicalCore
- testGlobalType
- []
- separation)
- definition <-
- maybe
- (assertFailure "separation did not form a set definition")
- pure
- (scopedSetDefinition
- (Foundation.foundationAxiomFrozen
- foundation
- Foundation.SeparationCharacteristic)
- body)
- let generated =
- instantiateCanonical
- separation
- (scopedCoreTerm definition)
- expected =
- betaNormalize
- (specializeForall predicate
- (specializeForall bound
- (mapCanonicalGlobals absurd
- (frozenCoreTerm
- (Foundation.foundationAxiomFrozen
- foundation
- Foundation.SeparationCharacteristic)))))
- assertEqual
- "local characteristic is the checked rule specialization"
- expected
- generated
-
-specializesCheckedReplacementCharacteristic :: Assertion
-specializesCheckedReplacementCharacteristic = do
- foundation <-
- either
- (assertFailure . show)
- pure
- Foundation.checkedFoundation
- pair <- checked [] (CGlobal TestPairGlobal)
- domain <- checked [] (CIntrinsic Empty)
- value <- checked [TySet] (CBound 0)
- (graph, checkedDomain, function) <-
- maybe
- (assertFailure "checked values did not form a replacement graph")
- pure
- (scopedReplacementGraph pair domain value)
- definition <-
- maybe
- (assertFailure "replacement graph did not form a definition")
- pure
- (scopedCharacteristicDefinition
- (Foundation.foundationAxiomFrozen
- foundation
- Foundation.ReplacementCharacteristic)
- graph
- (checkedDomain :| [function]))
- let generated =
- instantiateCanonical
- (scopedCoreTerm graph)
- (scopedCoreTerm definition)
- expected =
- betaNormalize
- (specializeForall (scopedCoreTerm function)
- (specializeForall (scopedCoreTerm checkedDomain)
- (mapCanonicalGlobals absurd
- (frozenCoreTerm
- (Foundation.foundationAxiomFrozen
- foundation
- Foundation.ReplacementCharacteristic)))))
- assertEqual
- "local graph characteristic is the checked rule specialization"
- expected
- generated
- where
- checked context term =
- either
- (assertFailure . show)
- pure
- (checkScopedCanonicalCore testGlobalType context term)
-
-derivesNamedConstructionViews :: Assertion
-derivesNamedConstructionViews = do
- foundation <-
- either (assertFailure . show) pure Foundation.checkedFoundation
- bound <- checked [] (CIntrinsic Empty)
- predicate <- checked [TySet] (CEq TySet (CBound 0) (CBound 0))
- separation <-
- maybe
- (assertFailure "checked separation descriptor failed")
- pure
- (checkedSeparationConstruction testGlobalType bound predicate)
- (separationView, separationEquation) <-
- maybe
- (assertFailure "checked separation views failed")
- pure
- (namedSetConstructionLocalViews
- (checkedFoundationSetConstruction foundation)
- separation)
- expectedSeparationView <-
- maybe
- (assertFailure "checked separation characteristic failed")
- pure
- (scopedSetDefinition
- (Foundation.foundationAxiomFrozen foundation
- Foundation.SeparationCharacteristic)
- (namedSetConstructionTerm separation))
- assertEqual "separation view is the checked specialization"
- expectedSeparationView separationView
- assertEqual "separation view is first-order"
- (Set.singleton Foundation.EmptyCharacteristic)
- (Foundation.foundationAxiomDependencies
- (scopedCoreTerm separationView))
- assertEqual "separation equation retains exact construction"
- (Set.fromList
- [ Foundation.EmptyCharacteristic
- , Foundation.SeparationCharacteristic
- ])
- (Foundation.foundationAxiomDependencies
- (scopedCoreTerm separationEquation))
-
- firstDomain <- checked [] (CIntrinsic Empty)
- singleValue <- checked [TySet] (CBound 0)
- singleCondition <- checked [TySet]
- (CEq TySet (CBound 0) (CBound 0))
- singleReplacement <-
- maybe
- (assertFailure "checked one-domain replacement failed")
- pure
- (checkedFunctionalReplacementConstruction
- testGlobalType
- (firstDomain :| [])
- singleValue
- (Just singleCondition))
- assertEqual "one-domain replacement has one canonical term"
- (CApp
- (CApp
- (CIntrinsic Repl)
- (CApp
- (CApp (CIntrinsic Sep) (CIntrinsic Empty))
- (CLam TySet
- (CEq TySet (CBound 0) (CBound 0)))))
- (CLam TySet (CBound 0)))
- (scopedCoreTerm
- (namedSetConstructionTerm singleReplacement))
-
- secondDomain <- checked [TySet] (CBound 0)
- value <- checked [TySet, TySet] (CBound 0)
- condition <- checked [TySet, TySet]
- (CEq TySet (CBound 0) (CBound 0))
- replacement <-
- maybe
- (assertFailure "checked replacement descriptor failed")
- pure
- (checkedFunctionalReplacementConstruction
- testGlobalType
- (firstDomain :| [secondDomain])
- value
- (Just condition))
- (replacementView, replacementEquation) <-
- maybe
- (assertFailure "checked replacement views failed")
- pure
- (namedSetConstructionLocalViews
- (checkedFoundationSetConstruction foundation)
- replacement)
- let terminal =
- andP
- (CEq TySet (CBound 0) (CBound 0))
- (CEq TySet (CBound 2) (CBound 0))
- secondWitness =
- existsP
- (andP
- (memberP (CBound 0) (CBound 1))
- terminal)
- firstWitness =
- existsP
- (andP
- (memberP (CBound 0) (CIntrinsic Empty))
- secondWitness)
- expectedReplacementTerm =
- CForall TySet
- (CEq TyProp
- (memberP (CBound 0) (CBound 1))
- firstWitness)
- expectedReplacementView <- checked [TySet] expectedReplacementTerm
- assertEqual "replacement view preserves bounds and condition"
- expectedReplacementView replacementView
- assertEqual "flattened replacement view is first-order"
- (Set.singleton Foundation.EmptyCharacteristic)
- (Foundation.foundationAxiomDependencies
- (scopedCoreTerm replacementView))
- assertEqual "replacement equation retains every helper"
- (Set.fromList
- [ Foundation.FamilyUnionCharacteristic
- , Foundation.EmptyCharacteristic
- , Foundation.SeparationCharacteristic
- , Foundation.ReplacementCharacteristic
- ])
- (Foundation.foundationAxiomDependencies
- (scopedCoreTerm replacementEquation))
- where
- checked context term =
- either
- (assertFailure . show)
- pure
- (checkScopedCanonicalCore testGlobalType context term)
-
- memberP element set =
- CApp (CApp (CIntrinsic Member) element) set
-
- notP proposition = CImp proposition CFalsum
-
- andP left right =
- notP (CImp left (notP right))
-
- existsP proposition =
- notP (CForall TySet (notP proposition))
-
-specializeForall
- :: CanonicalTerm global
- -> CanonicalTerm global
- -> CanonicalTerm global
-specializeForall argument = \case
- CForall _binderType body ->
- instantiateCanonical argument body
- _ ->
- error "the checked characteristic lost a binder"
-
-betaNormalize :: CanonicalTerm global -> CanonicalTerm global
-betaNormalize = \case
- CApp function argument ->
- case betaNormalize function of
- CLam _binderType body ->
- betaNormalize
- (instantiateCanonical
- (betaNormalize argument)
- body)
- normalizedFunction ->
- CApp normalizedFunction (betaNormalize argument)
- CLam binderType body ->
- CLam binderType (betaNormalize body)
- CImp premise conclusion ->
- CImp
- (betaNormalize premise)
- (betaNormalize conclusion)
- CEq operandType left right ->
- CEq operandType
- (betaNormalize left)
- (betaNormalize right)
- CForall binderType body ->
- CForall binderType (betaNormalize body)
- term -> term
-
-thawsCheckedClosedTerms :: Assertion
-thawsCheckedClosedTerms = do
- let source =
- coreLambda TySet (0 :: Int)
- (coreForall TySet 1
- (coreEquality
- TySet
- (coreLocal 0)
- (coreLocal 1)))
- freeze syntax = do
- checked <-
- either
- (assertFailure . show)
- pure
- (checkClosedCore testGlobalType syntax)
- either
- (assertFailure . show)
- pure
- (freezeClosed checked)
- original <-
- freeze source
- roundTrip <-
- freeze (thawFrozenCore original)
- assertEqual "frozen term" original roundTrip
- assertEqual
- "global inventory"
- mempty
- (frozenCoreGlobals original)
-
-prop_freezeAgreesWithReference :: Property
-prop_freezeAgreesWithReference = property do
- depth <-
- forAll (Gen.int (Range.linear 1 10))
- binderTypes <-
- forAll
- (Gen.list
- (Range.singleton depth)
- (Gen.element
- [ TyProp
- , TySet
- , TySet `TyArrow` TySet
- ]))
- selected <-
- forAll
- (Gen.maybe
- (Gen.int (Range.linear 0 (depth - 1))))
- let binders =
- zip [0 :: Int ..] binderTypes
- body =
- maybe
- (coreGlobal TestGlobal)
- coreLocal
- selected
- term =
- foldr
- (\(local, binderType) ->
- coreLambda binderType local)
- body
- binders
- checked <-
- evalEither
- (checkClosedCore testGlobalType term)
- optimized <-
- evalEither (force <$> freezeClosed checked)
- reference <-
- evalEither (force <$> referenceFreezeClosed checked)
- optimized === reference
diff --git a/source/Test/Unit/Declaration.hs b/source/Test/Unit/Declaration.hs
deleted file mode 100644
index 32d979c..0000000
--- a/source/Test/Unit/Declaration.hs
+++ /dev/null
@@ -1,3596 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module Test.Unit.Declaration (unitTests) where
-
-import Base
-import Checking.Authority qualified as Authority
-import Checking.Backend.Problem qualified as Backend
-import Checking.Core qualified as Core
-import Checking.Declaration qualified as Declaration
-import Checking.Foundation qualified as Foundation
-import Checking.Exact qualified as Exact
-import Checking.Exact.Vocabulary qualified as Vocabulary
-import Checking.Identity qualified as Identity
-import Checking.Kernel.Derivation qualified as Kernel
-import Checking.SetConstruction qualified as SetConstruction
-import Checking.Semantic qualified as Semantic
-import Checking.Typed.Inductive qualified as Typed
-import Felix.Math.Codec
-import Felix.Module
-import Felix.Source
-import Felix.Store qualified as Store
-import Felix.Meaning qualified as Meaning
-import Felix.Provers qualified as Provers
-import Report.Location
-import Syntax.Abstract qualified as Raw
-import Syntax.Interface qualified as Syntax
-import Syntax.Internal qualified as Internal
-import Syntax.Lexicon qualified as Lexicon
-
-import Data.List.NonEmpty qualified as NonEmpty
-import Data.IORef qualified as IORef
-import Data.Set qualified as Set
-import Data.Text qualified as Text
-import Data.Text.Encoding qualified as TextEncoding
-import Data.Vector qualified as Vector
-import Numeric.Natural (Natural)
-import Control.Exception (bracket)
-import Control.Exception qualified as Exception
-import Control.Monad.Except (runExceptT)
-import Control.Monad.State (evalState)
-import System.Directory qualified as Directory
-import System.FilePath.Posix qualified as Posix
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "Typed declaration seam"
- [ testCase "enforces staged candidate order"
- enforcesStagedCandidateOrder
- , testCase "retains only appended declaration prefixes"
- retainsOnlyAppendedPrefixes
- , testCase "makes declaration failures terminal"
- makesDeclarationFailuresTerminal
- , testCase "propagates unsafe authority through local claims"
- propagatesUnsafeAuthorityThroughLocalClaims
- , testCase "aggregates exact Vampire obligations"
- aggregatesExactVampireObligations
- , testCase "validates complete resolver batches before rejection"
- validatesCompleteResolverBatchesBeforeRejection
- , testCase "rejects retained-plan admission drift fatally"
- rejectsRetainedPlanAdmissionDrift
- , testCase "preserves source-axiom safety through Vampire validation"
- preservesSourceAxiomSafetyThroughVampireValidation
- , testCase "materializes a sealed import with fresh authority"
- materializesSealedImport
- , testCase "reconstructs exact imported global bindings"
- reconstructsImportedGlobalBindings
- , testCase "elaborates scoped exact propositions"
- elaboratesScopedExactPropositions
- , testCase "lowers fixed equality aliases without global support"
- lowersFixedEqualityAliases
- , testCase "scopes quantified proposition terms"
- scopesQuantifiedPropositionTerms
- , testCase "prepares exact claim envelopes"
- preparesExactClaimEnvelopes
- , testCase "lowers exact separation comprehensions"
- lowersExactSeparationComprehensions
- , testCase "lowers exact replacement telescopes"
- lowersExactReplacementTelescopes
- , testCase "lowers exact finite sets"
- lowersExactFiniteSets
- , testCase "lowers exact ordinary declarations"
- lowersExactOrdinaryDeclarations
- , testCase "folds transitive and diamond import evidence"
- foldsTransitiveAndDiamondEvidence
- , testCase "validates exact kernel construction descriptors"
- validatesExactKernelConstructionDescriptors
- , testCase "authorizes exact datatype compilation families"
- authorizesExactDatatypeCompilationFamilies
- , testCase "reuses exact compiled declaration validation"
- reusesExactCompiledDeclarationValidation
- , testCase "keeps fatal validation lookup failures out of declarations"
- keepsFatalValidationLookupFailuresOutOfDeclarations
- ]
-
-data FatalValidationLookup = FatalValidationLookup
- deriving (Show)
-
-instance Exception.Exception FatalValidationLookup
-
-keepsFatalValidationLookupFailuresOutOfDeclarations :: Assertion
-keepsFatalValidationLookupFailuresOutOfDeclarations = do
- fixture <- makeFixture
- prepared <- makePreparedObligation
- fixture
- Foundation.EmptyCharacteristic
- let lookup = proofOnlyValidationLookup
- (const (Exception.throwIO FatalValidationLookup))
- action = Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "fatal-validation-lookup") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "fatal-validation-lookup")
- Declaration.authorizeVampireCandidate candidate
- (Declaration.acceptVampireObligation prepared)
- result <- Exception.try
- (runDriverWithValidation fixture lookup action)
- :: IO
- (Either
- FatalValidationLookup
- (Declaration.DriverResult
- Void
- ((), Declaration.CommittedDeclarationBatch)))
- case result of
- Left FatalValidationLookup -> pure ()
- Right _ ->
- assertFailure "fatal validation lookup became a driver result"
-
-enforcesStagedCandidateOrder :: Assertion
-enforcesStagedCandidateOrder = do
- fixture <- makeFixture
- accepted <- runSuccessful fixture do
- result <- Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId "staged-success") do
- first <- Declaration.reserveCandidate
- (factSpec fixture "first")
- later <- Declaration.reserveCandidateBatch
- ( factSpec fixture "later-a"
- :| [factSpec fixture "later-b"]
- )
- Declaration.authorizeCompiledDeclaration do
- Declaration.authorizeSourceAxiomCandidate first
- traverse_
- (\candidate ->
- Declaration.authorizeKernelProofCandidate
- candidate do
- premise <-
- Declaration.useStagedCandidate first
- pure
- (Kernel.importedFactDerivation premise))
- later
- pure result
- let (_value, batch) = accepted
- assertEqual
- "all source-ordered candidates appended"
- 3
- (length
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch)))
-
- provenance <- runDriver fixture (priorDeclarationUse fixture)
- case provenance of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- (Declaration.CandidateOutsideDeclaration slot))
- prefix -> do
- assertEqual
- "cross-declaration staged premise"
- (localFact fixture 0)
- slot
- assertSingleCompletedPrefix prefix
- _other ->
- assertFailure
- "cross-declaration staged provenance was not rejected"
-
- traverse_
- (\(label, action, expectedPremise, expectedCandidate) -> do
- result <- runDriver fixture action
- case result of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- (Declaration.StagedPremiseNotEarlier
- premiseSlot premiseStage
- candidateSlot candidateStage))
- _prefix -> do
- assertEqual (label <> " premise slot")
- expectedPremise premiseSlot
- assertEqual (label <> " candidate slot")
- expectedCandidate candidateSlot
- assertBool (label <> " rejected non-earlier stage")
- (premiseStage >= candidateStage)
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed other)
- _prefix ->
- assertFailure
- (label <> ": unexpected error " <> show other)
- Declaration.DriverFailed
- (Declaration.DriverActionFailed _failure)
- _prefix ->
- assertFailure
- (label <> ": unexpected ordinary driver failure")
- Declaration.DriverSucceeded{} ->
- assertFailure (label <> ": invalid staged use succeeded")
- Declaration.DriverSealFailed{} ->
- assertFailure (label <> ": invalid staged use reached sealing"))
- [ ( "self"
- , selfUse fixture
- , localFact fixture 0
- , localFact fixture 0
- )
- , ( "same stage"
- , sameStageUse fixture
- , localFact fixture 1
- , localFact fixture 0
- )
- , ( "forward"
- , forwardUse fixture
- , localFact fixture 1
- , localFact fixture 0
- )
- ]
- where
- localFact fixture ordinal =
- Semantic.factSlot
- (fixtureOwner fixture)
- (localFactOrdinal ordinal)
-
- selfUse fixture =
- Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId "self") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "self")
- Declaration.authorizeCompiledDeclaration
- (Declaration.authorizeKernelProofCandidate candidate do
- premise <- Declaration.useStagedCandidate candidate
- pure (Kernel.importedFactDerivation premise))
-
- sameStageUse fixture =
- Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId "same-stage") do
- candidates <- Declaration.reserveCandidateBatch
- ( factSpec fixture "same-a"
- :| [factSpec fixture "same-b"]
- )
- let first = NonEmpty.head candidates
- second = NonEmpty.last candidates
- Declaration.authorizeCompiledDeclaration
- (Declaration.authorizeKernelProofCandidate first do
- premise <- Declaration.useStagedCandidate second
- pure (Kernel.importedFactDerivation premise))
-
- forwardUse fixture =
- Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId "forward") do
- first <- Declaration.reserveCandidate
- (factSpec fixture "forward-a")
- second <- Declaration.reserveCandidate
- (factSpec fixture "forward-b")
- Declaration.authorizeCompiledDeclaration
- (Declaration.authorizeKernelProofCandidate first do
- premise <- Declaration.useStagedCandidate second
- pure (Kernel.importedFactDerivation premise))
-
- priorDeclarationUse fixture = do
- (premise, _batch) <- Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId "prior-stage") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "prior-stage")
- Declaration.authorizeCompiledDeclaration
- (Declaration.authorizeSourceAxiomCandidate candidate)
- pure candidate
- void
- (Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId "later-stage") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "later-stage")
- Declaration.authorizeCompiledDeclaration
- (Declaration.authorizeKernelProofCandidate candidate do
- imported <-
- Declaration.useStagedCandidate premise
- pure (Kernel.importedFactDerivation imported)))
-
-retainsOnlyAppendedPrefixes :: Assertion
-retainsOnlyAppendedPrefixes = do
- fixture <- makeFixture
- outcome <- runDriver fixture do
- (_value, _firstBatch) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "accepted") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "accepted")
- Declaration.authorizeSourceAxiomCandidate candidate
- Declaration.failModuleDriver
- ("later checker failure" :: Text)
- case outcome of
- Declaration.DriverFailed
- (Declaration.DriverActionFailed reason) prefix -> do
- assertEqual
- "driver reports the later ordinary failure"
- "later checker failure"
- reason
- assertSingleCompletedPrefix prefix
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed err) _prefix ->
- assertFailure
- ("unexpected declaration failure: " <> show err)
- Declaration.DriverSucceeded{} ->
- assertFailure "ordinary driver failure was lost"
- Declaration.DriverSealFailed{} ->
- assertFailure "ordinary driver failure became a seal failure"
-
-makesDeclarationFailuresTerminal :: Assertion
-makesDeclarationFailuresTerminal = do
- fixture <- makeFixture
- outcome <- runDriver fixture do
- void
- (Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "accepted-before-failure") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "accepted-before-failure")
- Declaration.authorizeSourceAxiomCandidate candidate)
- void
- (Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId "rolled-back") do
- void
- (Declaration.reserveCandidate
- (factSpec fixture "uncommitted")))
- -- This declaration must be unreachable after the terminal failure.
- void
- (Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "must-not-publish") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "must-not-publish")
- Declaration.authorizeSourceAxiomCandidate candidate)
- case outcome of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- Declaration.DeclarationHasUnauthorizedCandidates)
- prefix ->
- assertSingleCompletedPrefix prefix
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed other) _prefix ->
- assertFailure
- ("unexpected declaration failure: " <> show other)
- Declaration.DriverFailed
- (Declaration.DriverActionFailed _failure) _prefix ->
- assertFailure "unexpected ordinary driver failure"
- Declaration.DriverSucceeded{} ->
- assertFailure "failed declaration was skipped"
- Declaration.DriverSealFailed{} ->
- assertFailure "failed declaration reached sealing"
-
-assertSingleCompletedPrefix
- :: Declaration.PendingModulePrefix
- -> Assertion
-assertSingleCompletedPrefix prefix = do
- let batches =
- Declaration.pendingModulePrefixBatches prefix
- assertEqual "one completed envelope survives" 1 (length batches)
- case batches of
- [batch] -> do
- let expected =
- Declaration.committedBatchNextPrefix batch
- assertEqual
- "failed declaration did not advance the prefix"
- expected
- (Declaration.pendingModulePrefixCurrent prefix)
- assertEqual
- "retained envelope ends at the exposed prefix"
- expected
- (Declaration.committedBatchNextPrefix batch)
- _ -> pure ()
-
-propagatesUnsafeAuthorityThroughLocalClaims :: Assertion
-propagatesUnsafeAuthorityThroughLocalClaims = do
- fixture <- makeFixture
- result <- runSuccessful fixture do
- (_sourceValue, sourceBatch) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "source-axiom") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "source")
- Declaration.authorizeSourceAxiomCandidate candidate
- sourceOccurrence <- requireSingleOccurrence sourceBatch
- let
- sourceFingerprint =
- Semantic.semanticFactFingerprint sourceOccurrence
- (_derivedValue, derivedBatch) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "local-claim") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "derived")
- Declaration.authorizeKernelProofCandidate candidate do
- sourcePremise <-
- Declaration.useAuthorizedFact sourceFingerprint
- claim <- Declaration.proveLocalKernelClaim
- (fixtureProposition fixture)
- (Kernel.importedFactDerivation sourcePremise)
- claimPremise <- Declaration.useLocalClaim claim
- pure (Kernel.importedFactDerivation claimPremise)
- pure derivedBatch
- occurrence <-
- case Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta result) of
- [single] -> pure single
- facts ->
- assertFailure
- ("unexpected fact count: " <> show (length facts))
- >> fail "unreachable"
- let authority = Semantic.semanticFactAuthority occurrence
- assertEqual
- "local claim cannot erase source-axiom safety"
- (Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.SourceAxiom))
- (Authority.factAuthoritySafety authority)
- case Declaration.committedBatchProofValidations result of
- [record] ->
- assertEqual
- "local support is absent from the compact direct authorization"
- (Authority.CheckedSourceProof [])
- (Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate record))
- records ->
- assertFailure
- ("unexpected proof validation count: "
- <> show (length records))
-
-aggregatesExactVampireObligations :: Assertion
-aggregatesExactVampireObligations =
- withTemporaryDirectory "felix-declaration-vampire" \root -> do
- fixture <- makeFixture
- let executable = root Posix.</> "vampire"
- writeAcceptedVampire executable
- first <- makePreparedObligation
- fixture
- Foundation.EmptyCharacteristic
- second <- makePreparedObligation
- fixture
- Foundation.PairSetCharacteristic
- let exactResolver = acceptedResolver executable
- freshOutcome <-
- (runDriverWithResolver fixture exactResolver do
- (_value, committed) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "two-vampire-obligations") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "two-vampire-obligations")
- Declaration.authorizeVampireCandidate candidate do
- Declaration.acceptVampireObligation first
- Declaration.acceptVampireObligation second
- pure committed
- :: IO
- (Declaration.DriverResult Text
- Declaration.CommittedDeclarationBatch))
- (batch, freshPrefix) <-
- case freshOutcome of
- Declaration.DriverSucceeded value _ prefix _closure ->
- pure (value, prefix)
- Declaration.DriverFailed failure _ ->
- assertFailure
- ("fresh Vampire fixture failed: " <> show failure)
- >> fail "unreachable"
- Declaration.DriverSealFailed failure _ ->
- assertFailure
- ("fresh Vampire fixture did not seal: "
- <> show failure)
- >> fail "unreachable"
- let expectedRequests =
- Provers.preparedVerificationRequestId
- (Provers.preparedTypedProverRequest first)
- : [Provers.preparedVerificationRequestId
- (Provers.preparedTypedProverRequest second)]
- case Declaration.committedBatchProofValidations batch of
- [record] ->
- assertEqual
- "accepted requests retain source order"
- (Authority.CheckedSourceProof expectedRequests)
- (Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate record))
- records ->
- assertFailure
- ("unexpected proof validation count: "
- <> show (length records))
-
- cachedRecord <-
- case Declaration.committedBatchProofValidations batch of
- [record] -> pure record
- records ->
- assertFailure
- ("unexpected cached proof records: "
- <> show (length records))
- >> fail "unreachable"
- cachedLookupKey <- IORef.newIORef Nothing
- cached <- runSuccessfulWithValidation fixture
- (proofOnlyValidationLookup
- (\key -> do
- IORef.writeIORef cachedLookupKey (Just key)
- pure (Just cachedRecord))) do
- (_value, committed) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "two-vampire-obligations") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "two-vampire-obligations")
- Declaration.authorizeVampireCandidate candidate do
- Declaration.acceptVampireObligation first
- Declaration.acceptVampireObligation second
- pure committed
- publishedRecord <-
- case Declaration.committedBatchProofValidations cached of
- [record] -> pure record
- records ->
- assertFailure
- ("unexpected cached validation records: "
- <> show (length records))
- >> fail "unreachable"
- assertEqual
- "cached authorization preserves the exact direct proof"
- (Authority.CheckedSourceProof expectedRequests)
- (Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate publishedRecord))
- assertEqual
- "lookup and publication retain the same validation key"
- (Semantic.proofValidationRecordKey cachedRecord)
- (Semantic.proofValidationRecordKey publishedRecord)
- assertEqual
- "one proof syntax key governs lookup and publication"
- (Just
- (Semantic.proofValidationRecordKey cachedRecord))
- =<< IORef.readIORef cachedLookupKey
-
- missLookups <- IORef.newIORef (0 :: Int)
- missRuns <- IORef.newIORef (0 :: Int)
- let missLookup = proofOnlyValidationLookup \_key -> do
- IORef.modifyIORef' missLookups (+ 1)
- pure Nothing
- missResolver = Declaration.vampireResolver \prepared -> do
- IORef.modifyIORef' missRuns (+ 1)
- resolveAccepted executable prepared
- miss <- runDriverWithValidationAndResolver
- fixture
- missLookup
- missResolver
- do
- (_value, committed) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "two-vampire-obligations") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "two-vampire-obligations")
- Declaration.authorizeVampireCandidate candidate do
- Declaration.acceptVampireObligation first
- Declaration.acceptVampireObligation second
- pure committed
- case miss of
- Declaration.DriverSucceeded{} -> pure ()
- _ ->
- assertFailure "warm miss failed"
- assertEqual "warm miss performs one exact lookup"
- 1
- =<< IORef.readIORef missLookups
- assertEqual "warm miss runs every reached Vampire request"
- 2
- =<< IORef.readIORef missRuns
-
- mismatchRuns <- IORef.newIORef (0 :: Int)
- let editedSyntax =
- Semantic.proofSyntaxId "edited-proof-syntax"
- cachedCertificate =
- Semantic.proofValidationRecordCertificate cachedRecord
- corruptedKey =
- Semantic.proofValidationKey
- (Identity.theoremId
- (Authority.factAuthorityTheorem
- (Authority.validationTarget
- cachedCertificate)))
- editedSyntax
- (Declaration.committedBatchPreviousPrefix batch)
- corruptedRecord =
- Semantic.proofValidationRecord
- corruptedKey
- cachedCertificate
- mismatchResolver = Declaration.vampireResolver \prepared -> do
- IORef.modifyIORef' mismatchRuns (+ 1)
- resolveAccepted executable prepared
- mismatchingLookup = proofOnlyValidationLookup
- (const (pure (Just corruptedRecord)))
- mismatching <- Exception.try
- (runDriverWithValidationAndResolver
- fixture
- mismatchingLookup
- mismatchResolver
- do
- Declaration.commitProofDeclaration editedSyntax do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "two-vampire-obligations")
- Declaration.authorizeVampireCandidate candidate
- (Declaration.acceptVampireObligation first))
- :: IO
- (Either
- Declaration.ValidationIntegrityError
- (Declaration.DriverResult
- Text
- ((), Declaration.CommittedDeclarationBatch)))
- case mismatching of
- Left Declaration.CachedValidationIntegrityError{} ->
- pure ()
- Right _ ->
- assertFailure "mismatching hit did not abort as corruption"
- assertEqual "mismatching hit does not fall back to Vampire"
- 0
- =<< IORef.readIORef mismatchRuns
-
- withOpenedStore fixture root \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store freshPrefix)
- warmCalls <- IORef.newIORef (0 :: Int)
- let storeLookup = proofOnlyValidationLookup \key -> do
- IORef.modifyIORef' warmCalls (+ 1)
- Store.loadProofValidation store key >>= expectRight
- warm <- runSuccessfulWithValidation fixture
- storeLookup
- do
- (_value, committed) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "two-vampire-obligations") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "two-vampire-obligations")
- Declaration.authorizeVampireCandidate candidate do
- Declaration.acceptVampireObligation first
- Declaration.acceptVampireObligation second
- pure committed
- assertEqual "warm lookup executes once through the store"
- 1
- =<< IORef.readIORef warmCalls
- assertEqual "warm path retains cached request IDs"
- (Authority.CheckedSourceProof expectedRequests)
- (case Declaration.committedBatchProofValidations warm of
- [record] ->
- Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate record)
- records ->
- error
- ("unexpected warm validation records: "
- <> show (length records)))
-
- emptyProof <- runDriver fixture do
- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "empty-vampire-proof") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "empty-vampire-proof")
- Declaration.authorizeVampireCandidate candidate
- (pure ())
- case emptyProof of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- Declaration.VampireProofHasNoAcceptedObligations)
- prefix ->
- assertEqual
- "empty Vampire proof publishes no declaration"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed other) _prefix ->
- assertFailure
- ("unexpected empty-proof failure: " <> show other)
- Declaration.DriverFailed
- (Declaration.DriverActionFailed _failure) _prefix ->
- assertFailure "unexpected ordinary driver failure"
- Declaration.DriverSucceeded{} ->
- assertFailure "empty Vampire proof was authorized"
- Declaration.DriverSealFailed{} ->
- assertFailure "empty Vampire proof reached sealing"
-
- invalidClosure <- expectRight
- (Identity.validateObjectClosure
- (Identity.theoryId (fixtureFoundation fixture))
- [])
- invalidTarget <- expectRight
- (Identity.validatePropositionContent
- invalidClosure
- (Core.CImp Core.CFalsum Core.CFalsum))
- invalidCalls <- IORef.newIORef (0 :: Int)
- let invalidResolver =
- Declaration.vampireResolver \prepared -> do
- IORef.modifyIORef' invalidCalls (+ 1)
- resolveAccepted executable prepared
- invalid <- runDriverWithResolver fixture invalidResolver do
- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "invalid-vampire-target") do
- candidate <- Declaration.reserveCandidate
- (Declaration.candidateSpec
- invalidTarget
- Semantic.SearchEligible
- [Semantic.semanticName
- "invalid-vampire-target"])
- Declaration.authorizeVampireCandidate candidate
- (Declaration.acceptVampireObligation first)
- assertEqual
- "invalid prepared problem does not invoke Vampire"
- 0
- =<< IORef.readIORef invalidCalls
- case invalid of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- Declaration.VampireTargetMismatch)
- prefix ->
- assertEqual
- "invalid prepared problem publishes no declaration"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed other) _prefix ->
- assertFailure
- ("unexpected prepared-problem failure: " <> show other)
- Declaration.DriverFailed
- (Declaration.DriverActionFailed _failure) _prefix ->
- assertFailure "unexpected ordinary driver failure"
- Declaration.DriverSucceeded{} ->
- assertFailure "invalid prepared problem was authorized"
- Declaration.DriverSealFailed{} ->
- assertFailure "invalid prepared problem reached sealing"
-
- let mismatchedResolver =
- Declaration.vampireResolver \_prepared ->
- resolveAccepted executable second
- mismatch <- runDriverWithResolver fixture mismatchedResolver do
- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "mismatched-vampire-request") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "mismatched-vampire-request")
- Declaration.authorizeVampireCandidate candidate
- (Declaration.acceptVampireObligation first)
- case mismatch of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- Declaration.VampireRequestMismatch)
- prefix ->
- assertEqual
- "mismatch publishes no declaration"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed other) _prefix ->
- assertFailure
- ("unexpected mismatch failure: " <> show other)
- Declaration.DriverFailed
- (Declaration.DriverActionFailed _failure) _prefix ->
- assertFailure "unexpected ordinary driver failure"
- Declaration.DriverSucceeded{} ->
- assertFailure "mismatched request was authorized"
- Declaration.DriverSealFailed{} ->
- assertFailure "mismatched request reached sealing"
-
- unrecorded <- runDriver fixture do
- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "unrecorded-omission") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "unrecorded-omission")
- Declaration.authorizeOmittedCandidate candidate
- (pure ())
- case unrecorded of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- Declaration.OmittedProofDidNotRecordUse)
- prefix ->
- assertEqual
- "unrecorded omission publishes no declaration"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed other) _prefix ->
- assertFailure
- ("unexpected unrecorded-omission failure: "
- <> show other)
- Declaration.DriverFailed
- (Declaration.DriverActionFailed _failure) _prefix ->
- assertFailure "unexpected ordinary driver failure"
- Declaration.DriverSucceeded{} ->
- assertFailure "unrecorded omission was authorized"
- Declaration.DriverSealFailed{} ->
- assertFailure "unrecorded omission reached sealing"
-
- calls <- IORef.newIORef (0 :: Int)
- let countingResolver =
- Declaration.vampireResolver \prepared -> do
- IORef.modifyIORef' calls (+ 1)
- resolveAccepted executable prepared
- omittedBatch <- runSuccessfulWithResolver fixture countingResolver do
- (_value, committed) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "omitted-after-obligations") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "omitted-after-obligations")
- Declaration.authorizeOmittedCandidate candidate do
- Declaration.acceptVampireObligation first
- Declaration.acceptVampireObligation second
- Declaration.recordOmittedUse
- pure committed
- assertEqual
- "omitted proof still checks preceding obligations"
- 2
- =<< IORef.readIORef calls
- case Declaration.committedBatchProofValidations omittedBatch of
- [record] ->
- assertEqual
- "omitted direct authorization discards request IDs"
- Authority.OmittedAuthorization
- (Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate record))
- records ->
- assertFailure
- ("unexpected omitted validation count: "
- <> show (length records))
-
-validatesCompleteResolverBatchesBeforeRejection :: Assertion
-validatesCompleteResolverBatchesBeforeRejection =
- withTemporaryDirectory "felix-declaration-batch-integrity" \root -> do
- fixture <- makeFixture
- let executable = root Posix.</> "vampire"
- firstLocation = mkLocation (FileId 76) 1 1
- secondLocation = mkLocation (FileId 76) 2 1
- writeAcceptedVampire executable
- mismatchedTask <-
- makePreparedObligation
- fixture
- Foundation.EmptyCharacteristic
- let integrityResolver =
- Declaration.vampireBatchResolver \_tasks -> do
- mismatched <- resolveAccepted executable mismatchedTask
- pure
- ( Right (Provers.CounterSatisfiable "earlier")
- :| [mismatched]
- )
- integrityOutcome <-
- (runDriverWithResolver fixture integrityResolver do
- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "batch-integrity-priority") do
- candidates <- Declaration.reserveCandidateBatch
- ( factSpec fixture "batch-integrity-first"
- :| [factSpec fixture "batch-integrity-second"]
- )
- Declaration.authorizeVampireCandidateBatch
- ( ( firstLocation
- , NonEmpty.head candidates
- , Declaration.prepareCurrentCandidateVampire
- )
- :| [ ( secondLocation
- , NonEmpty.last candidates
- , Declaration.prepareCurrentCandidateVampire
- )
- ]
- )
- :: IO
- (Declaration.DriverResult Text
- ((), Declaration.CommittedDeclarationBatch)))
- case integrityOutcome of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- (Declaration.ProofObligationFailedAt
- location
- Declaration.VampireRequestMismatch))
- prefix -> do
- assertEqual
- "later request mismatch retains its location"
- secondLocation
- location
- assertEqual
- "integrity failure rolls back the complete declaration"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("unexpected batch-integrity failure: " <> show failure)
- Declaration.DriverSucceeded{} ->
- assertFailure
- "earlier ordinary rejection concealed no integrity failure"
- Declaration.DriverSealFailed{} ->
- assertFailure "invalid batch reached module sealing"
-
- prepared <-
- makePreparedObligation
- fixture
- Foundation.EmptyCharacteristic
- let excessResolver =
- Declaration.vampireBatchResolver \_tasks ->
- pure
- ( Right (Provers.CounterSatisfiable "first")
- :| [Right (Provers.CounterSatisfiable "excess")]
- )
- excessOutcome <-
- (runDriverWithResolver fixture excessResolver do
- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "singleton-excess-result") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "singleton-excess-result")
- Declaration.authorizeVampireCandidate candidate
- (Declaration.acceptVampireObligation prepared)
- :: IO
- (Declaration.DriverResult Text
- ((), Declaration.CommittedDeclarationBatch)))
- case excessOutcome of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- (Declaration.VampireResolverBatchSizeMismatch 1 2))
- prefix ->
- assertEqual
- "malformed singleton response publishes no declaration"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("unexpected singleton-cardinality failure: "
- <> show failure)
- Declaration.DriverSucceeded{} ->
- assertFailure "singleton resolver ignored an excess result"
- Declaration.DriverSealFailed{} ->
- assertFailure "malformed singleton reached module sealing"
-
-rejectsRetainedPlanAdmissionDrift :: Assertion
-rejectsRetainedPlanAdmissionDrift = do
- fixture <- makeFixture
- let checked =
- Declaration.checkedProofDeclaration
- (Semantic.proofSyntaxId "planned-admission-drift")
- []
- []
- []
- []
- [ Declaration.checkedCandidate
- (factSpec fixture "planned-admission-drift")
- Declaration.checkedSourceAxiomPlanning
- :| []
- ]
- ()
- action = do
- planned <-
- Declaration.runProspectiveLoweringDriver
- (Declaration.planCheckedDeclaration checked)
- >>= either Declaration.failDeclarationDriver pure
- Declaration.admitPlannedCheckedDeclaration planned
- (\() stages ->
- case concatMap toList stages of
- [candidate] ->
- Declaration.authorizeOmittedCandidate candidate
- Declaration.recordOmittedUse
- _ -> error "planned drift fixture candidate shape")
- outcome <-
- Exception.try (runDriver fixture action)
- :: IO
- (Either
- Declaration.PlanningIntegrityError
- (Declaration.DriverResult
- Void
- Declaration.CommittedDeclarationBatch))
- case outcome of
- Left (Declaration.PlanningIntegrityError diagnostic) ->
- assertBool "fatal mismatch identifies prospective contract drift"
- ("prospective contract" `Text.isInfixOf` diagnostic)
- Right _ ->
- assertFailure
- "a changed admitted authority was accepted against its plan"
-
-preservesSourceAxiomSafetyThroughVampireValidation :: Assertion
-preservesSourceAxiomSafetyThroughVampireValidation =
- withTemporaryDirectory "felix-declaration-source-axiom" \root -> do
- fixture <- makeFixture
- let executable = root Posix.</> "vampire"
- writeAcceptedVampire executable
- prepared <-
- makePreparedObligationWithPremise
- fixture
- (fixtureSourceAxiomFingerprint fixture)
- freshCalls <- IORef.newIORef (0 :: Int)
- let freshResolver = Declaration.vampireResolver \task -> do
- IORef.modifyIORef' freshCalls (+ 1)
- resolveAccepted executable task
- freshOutcome <-
- (runDriverWithResolver fixture freshResolver
- (sourceAxiomThenVampire fixture prepared)
- :: IO
- (Declaration.DriverResult Text
- Declaration.CommittedDeclarationBatch))
- assertEqual
- "fresh source-axiom theorem invokes Vampire once"
- 1
- =<< IORef.readIORef freshCalls
- freshBatch <-
- case freshOutcome of
- Declaration.DriverSucceeded batch _ _ _closure ->
- pure batch
- Declaration.DriverFailed failure _ ->
- assertFailure
- ("fresh source-axiom driver failed: "
- <> show failure)
- >> fail "unreachable"
- Declaration.DriverSealFailed failure _ ->
- assertFailure
- ("fresh source-axiom driver did not seal: "
- <> show failure)
- >> fail "unreachable"
- let freshRecord = singleProofValidation freshBatch
- assertEqual
- "fresh theorem retains source-axiom safety"
- sourceAxiomSafety
- (Authority.factAuthoritySafety
- (Authority.validationTarget
- (Semantic.proofValidationRecordCertificate freshRecord)))
- separationCalls <- IORef.newIORef (0 :: Int)
- let separationResolver = Declaration.vampireResolver \task -> do
- IORef.modifyIORef' separationCalls (+ 1)
- resolveAccepted executable task
- separated <-
- (runDriverWithResolver fixture separationResolver do
- void
- (Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "source-axiom") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "source-axiom")
- Declaration.authorizeSourceAxiomCandidate candidate)
- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "atp-does-not-import") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "atp-does-not-import")
- Declaration.authorizeKernelProofCandidate candidate do
- Declaration.acceptVampireObligation prepared
- pure
- (Kernel.importedFactDerivation
- (Kernel.importIx 0))
- :: IO
- (Declaration.DriverResult Text
- ((), Declaration.CommittedDeclarationBatch)))
- assertEqual "mixed proof executes its ATP obligation"
- 1
- =<< IORef.readIORef separationCalls
- case separated of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- (Declaration.KernelCompletionFailed
- (Kernel.KernelReplayImportOutOfBounds index)))
- prefix -> do
- assertEqual "ATP premise is absent from kernel imports"
- (Kernel.importIx 0)
- index
- assertEqual "failed mixed proof retains only its prefix"
- 1
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("unexpected mixed-proof failure: " <> show failure)
- Declaration.DriverSucceeded{} ->
- assertFailure "ATP premise entered the kernel import inventory"
- Declaration.DriverSealFailed{} ->
- assertFailure "mixed proof unexpectedly reached sealing"
- withOpenedStore fixture root \store -> do
- freshPrefix <-
- case freshOutcome of
- Declaration.DriverSucceeded _ _ prefix _closure ->
- pure prefix
- Declaration.DriverFailed failure _ ->
- assertFailure
- ("fresh source-axiom driver failed: "
- <> show failure)
- >> fail "unreachable"
- Declaration.DriverSealFailed failure _ ->
- assertFailure
- ("fresh source-axiom driver did not seal: "
- <> show failure)
- >> fail "unreachable"
- expectRightIO
- (Store.writePendingModulePrefix store freshPrefix)
- warmCalls <- IORef.newIORef (0 :: Int)
- let storeLookup = proofOnlyValidationLookup \key -> do
- IORef.modifyIORef' warmCalls (+ 1)
- Store.loadProofValidation store key >>= expectRight
- warmBatch <- runSuccessfulWithValidation fixture
- storeLookup
- (sourceAxiomThenVampire fixture prepared)
- assertEqual
- "warm source-axiom theorem performs one store lookup"
- 1
- =<< IORef.readIORef warmCalls
- assertEqual
- "warm theorem retains source-axiom safety"
- sourceAxiomSafety
- (Authority.factAuthoritySafety
- (Authority.validationTarget
- (Semantic.proofValidationRecordCertificate
- (singleProofValidation warmBatch))))
- where
- sourceAxiomSafety =
- Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.SourceAxiom)
-
- singleProofValidation batch =
- case Declaration.committedBatchProofValidations batch of
- [record] -> record
- records ->
- error
- ("unexpected proof validation count: "
- <> show (length records))
-
-sourceAxiomThenVampire
- :: Fixture
- -> Provers.PreparedTypedProverTask
- Semantic.SemanticFactOccurrenceFingerprint
- Void
- ()
- Identity.ObjectId
- -> Declaration.ModuleDriver failure
- Declaration.CommittedDeclarationBatch
-sourceAxiomThenVampire fixture prepared = do
- void
- (Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "source-axiom") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "source-axiom")
- Declaration.authorizeSourceAxiomCandidate candidate)
- (_value, batch) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "source-axiom-vampire") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "source-axiom-vampire")
- Declaration.authorizeVampireCandidate candidate
- (Declaration.acceptVampireObligation prepared)
- pure batch
-
-fixtureSourceAxiomFingerprint
- :: Fixture
- -> Semantic.SemanticFactOccurrenceFingerprint
-fixtureSourceAxiomFingerprint fixture =
- Semantic.semanticFactOccurrenceFingerprint
- (Semantic.factSlot
- (fixtureOwner fixture)
- (localFactOrdinal 0))
- (Authority.factAuthority
- (Identity.theoremRef
- (Identity.theoryId (fixtureFoundation fixture))
- (Identity.checkedPropositionId
- (fixtureProposition fixture)))
- (Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.SourceAxiom)))
-
-makePreparedObligationWithPremise
- :: Fixture
- -> Semantic.SemanticFactOccurrenceFingerprint
- -> IO
- (Provers.PreparedTypedProverTask
- Semantic.SemanticFactOccurrenceFingerprint
- Void
- ()
- Identity.ObjectId)
-makePreparedObligationWithPremise fixture fingerprint = do
- claim <- expectRight
- (Backend.supportedProposition
- (Vector.empty :: Vector.Vector (Void, Core.CoreType))
- (Core.embedClosedCore
- []
- (Identity.checkedPropositionTerm
- (fixtureProposition fixture))))
- factProposition <- expectRight
- (Backend.supportedProposition
- (Vector.empty :: Vector.Vector (Void, Core.CoreType))
- (Core.embedClosedCore
- []
- (Identity.checkedPropositionTerm
- (fixtureProposition fixture))))
- capability <- expectRight
- (Backend.classifySupportedProposition
- (const Nothing)
- factProposition)
- problem <- expectRight
- (Backend.planTypedProblem
- (const Nothing)
- (Vector.singleton
- (Backend.typedBackendFact
- fingerprint
- factProposition
- capability))
- claim
- []
- []
- Backend.FirstOrderLocals
- Backend.ExplicitHigherOrderJustification)
- expectRight
- (Provers.prepareTypedProverTask
- Provers.DirectTask
- problem)
-
-makePreparedObligation
- :: Fixture
- -> Foundation.FoundationAxiomTag
- -> IO
- (Provers.PreparedTypedProverTask
- Semantic.SemanticFactOccurrenceFingerprint
- Void
- ()
- Identity.ObjectId)
-makePreparedObligation fixture tag = do
- claim <- expectRight
- (Backend.supportedProposition
- (Vector.empty :: Vector.Vector (Void, Core.CoreType))
- (Core.embedClosedCore
- []
- (Identity.checkedPropositionTerm
- (fixtureProposition fixture))))
- problem <- expectRight
- (Backend.planTypedProblem
- (const Nothing)
- Vector.empty
- claim
- []
- [Backend.typedFoundationAuxiliaryInput
- (fixtureFoundation fixture)
- tag]
- Backend.CompleteLocals
- Backend.ExplicitHigherOrderJustification)
- expectRight
- (Provers.prepareTypedProverTask
- Provers.DirectTask
- problem)
-
-acceptedResolver :: FilePath -> Declaration.VampireResolver
-acceptedResolver executable =
- Declaration.vampireResolver (resolveAccepted executable)
-
-resolveAccepted
- :: FilePath
- -> Provers.PreparedTypedProverTask
- ref local origin global
- -> IO
- (Either
- Provers.ProverProcessError
- Provers.ProverAnswer)
-resolveAccepted executable prepared =
- Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared
-
-writeAcceptedVampire :: FilePath -> IO ()
-writeAcceptedVampire executable = do
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for typed'"
- ])
- permissions <- Directory.getPermissions executable
- Directory.setPermissions executable
- (Directory.setOwnerExecutable True permissions)
-
-validatesExactKernelConstructionDescriptors :: Assertion
-validatesExactKernelConstructionDescriptors = do
- fixture <- makeFixture
- proposition <- foundationProposition
- fixture
- Foundation.EmptyCharacteristic
- let declaredObject = opaqueFixtureObject fixture
- run descriptor =
- runDriver fixture
- (Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId
- "kernel-construction-descriptor") do
- Declaration.addDeclarationObject declaredObject
- candidate <- Declaration.reserveCandidate
- (Declaration.candidateSpec
- proposition
- Semantic.SearchEligible
- [Semantic.semanticName "kernel-construction"])
- Declaration.authorizeCompiledDeclaration
- (Declaration.authorizeKernelConstructionCandidate
- descriptor
- candidate
- (pure
- (Kernel.foundationFactDerivation
- Foundation.EmptyCharacteristic))))
- success <- run
- (Authority.FoundationLeaf
- Foundation.EmptyCharacteristic)
- case success of
- Declaration.DriverSucceeded (_value, batch) _interface _prefix _closure -> do
- assertEqual
- "new object is included in the checked declaration batch"
- 1
- (length (Declaration.committedBatchObjects batch))
- case Declaration.committedBatchDeclarationValidation batch of
- Just record ->
- case Semantic.declarationValidationRecordCertificates
- record of
- [certificate] ->
- assertEqual
- "exact kernel descriptor is retained"
- (Authority.CheckedKernelConstruction
- (Authority.FoundationLeaf
- Foundation.EmptyCharacteristic))
- (Authority.validationDirectAuthorization
- certificate)
- certificates ->
- assertFailure
- ("unexpected kernel certificate count: "
- <> show (length certificates))
- Nothing ->
- assertFailure "missing declaration validation"
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed failure) _prefix ->
- assertFailure
- ("valid kernel descriptor failed: " <> show failure)
- Declaration.DriverFailed
- (Declaration.DriverActionFailed _failure) _prefix ->
- assertFailure "unexpected ordinary driver failure"
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure (show failure)
-
- traverse_
- (\(label, descriptor) -> do
- outcome <- run descriptor
- case outcome of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- Declaration.KernelConstructionDescriptorMismatch)
- prefix ->
- assertEqual
- (label <> " publishes no declaration")
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed other)
- _prefix ->
- assertFailure
- (label <> ": unexpected error " <> show other)
- Declaration.DriverFailed
- (Declaration.DriverActionFailed _failure)
- _prefix ->
- assertFailure (label <> ": ordinary driver failure")
- Declaration.DriverSucceeded{} ->
- assertFailure (label <> ": mismatch was accepted")
- Declaration.DriverSealFailed{} ->
- assertFailure (label <> ": mismatch reached sealing"))
- [ ( "wrong foundation leaf"
- , Authority.FoundationLeaf
- Foundation.PairSetCharacteristic
- )
- , ( "wrong construction family"
- , Authority.GuardedFoundationRules
- (Authority.guardedRuleSet
- (Foundation.SetLfpBound :| []))
- )
- ]
-
-authorizesExactDatatypeCompilationFamilies :: Assertion
-authorizesExactDatatypeCompilationFamilies = do
- fixture <- makeFixture
- firstProposition <- foundationProposition
- fixture
- Foundation.EmptyCharacteristic
- secondProposition <- foundationProposition
- fixture
- Foundation.PairSetCharacteristic
- let carrier = datatypeFixtureObject fixture 0
- constructor = datatypeFixtureObject fixture 1
- carrierId = Identity.assertedObjectId carrier
- constructorId = Identity.assertedObjectId constructor
- references =
- fmap
- (Identity.theoremRef
- (Identity.theoryId
- (fixtureFoundation fixture))
- . Identity.checkedPropositionId)
- [firstProposition, secondProposition]
- descriptor =
- Authority.datatypeCompilationDescriptor
- carrierId
- (constructorId :| [])
- references
- action
- :: Authority.DatatypeCompilationDescriptor
- -> Declaration.ModuleDriver Text
- ((), Declaration.CommittedDeclarationBatch)
- action suppliedDescriptor =
- Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId "datatype-compilation") do
- traverse_ Declaration.addDeclarationObject
- [carrier, constructor]
- candidates <-
- Declaration.reserveCandidateBatch
- ( Declaration.candidateSpec
- firstProposition
- Semantic.SearchEligible
- [Semantic.semanticName "datatype-first"]
- :| [ Declaration.candidateSpec
- secondProposition
- Semantic.SearchEligible
- [Semantic.semanticName "datatype-second"]
- ]
- )
- Declaration.authorizeCompiledDeclaration
- (Declaration.authorizeDatatypeCompilationCandidates
- suppliedDescriptor
- carrierId
- (constructorId :| [])
- candidates)
-
- (_value, batch) <- runSuccessful fixture (action descriptor)
- assertEqual "complete object family was published"
- [carrier, constructor]
- (Declaration.committedBatchObjects batch)
- case Declaration.committedBatchDeclarationValidation batch of
- Just record -> do
- let certificates =
- Semantic.declarationValidationRecordCertificates record
- assertEqual "complete fact family was authorized" 2
- (length certificates)
- traverse_
- (\certificate -> do
- assertEqual "datatype authority is clean"
- Authority.cleanAuthoritySafety
- (Authority.factAuthoritySafety
- (Authority.validationTarget certificate))
- assertEqual "one descriptor protects every member"
- (Authority.TrustedCompilation
- (Authority.DatatypeCompilation descriptor))
- (Authority.validationDirectAuthorization certificate))
- certificates
- Nothing ->
- assertFailure "datatype compilation omitted validation"
-
- let mismatched =
- Authority.datatypeCompilationDescriptor
- carrierId
- (constructorId :| [])
- (reverse references)
- rejected <- runDriver fixture (action mismatched)
- case rejected of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- Declaration.DatatypeCompilationDescriptorMismatch)
- prefix ->
- assertEqual "mismatched family publishes no declaration"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("unexpected datatype-family failure: " <> show failure)
- Declaration.DriverSucceeded{} ->
- assertFailure "mismatched datatype family was authorized"
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure
- ("mismatched datatype family reached sealing: "
- <> show failure)
-
-reusesExactCompiledDeclarationValidation :: Assertion
-reusesExactCompiledDeclarationValidation = do
- fixture <- makeFixture
- proposition <- foundationProposition
- fixture
- Foundation.EmptyCharacteristic
- let declaredObject = opaqueFixtureObject fixture
- syntax =
- Semantic.declarationSyntaxId
- "cached-kernel-construction"
- action derivationTag =
- Declaration.commitCompiledDeclaration syntax do
- Declaration.addDeclarationObject declaredObject
- candidate <- Declaration.reserveCandidate
- (Declaration.candidateSpec
- proposition
- Semantic.SearchEligible
- [Semantic.semanticName
- "cached-kernel-construction"])
- Declaration.authorizeCompiledDeclaration
- (Declaration.authorizeKernelConstructionCandidate
- (Authority.FoundationLeaf
- Foundation.EmptyCharacteristic)
- candidate
- (pure
- (Kernel.foundationFactDerivation
- derivationTag)))
- freshBatch <- runSuccessful fixture
- (snd <$> action Foundation.EmptyCharacteristic)
- freshRecord <-
- case Declaration.committedBatchDeclarationValidation freshBatch of
- Just record -> pure record
- Nothing ->
- assertFailure "fresh compiled declaration omitted validation"
- >> fail "unreachable"
-
- missLookups <- IORef.newIORef (0 :: Int)
- missBatch <- runSuccessfulWithValidation fixture
- (compiledOnlyValidationLookup \_key -> do
- IORef.modifyIORef' missLookups (+ 1)
- pure Nothing)
- (snd <$> action Foundation.EmptyCharacteristic)
- assertEqual "compiled warm miss performs one exact lookup"
- 1
- =<< IORef.readIORef missLookups
- assertBool "compiled miss publishes fresh validation"
- (isJust
- (Declaration.committedBatchDeclarationValidation missBatch))
-
- hitLookups <- IORef.newIORef []
- hitBatch <- runSuccessfulWithValidation fixture
- (compiledOnlyValidationLookup \key -> do
- IORef.modifyIORef' hitLookups (key :)
- pure (Just freshRecord))
- (snd <$> action Foundation.PairSetCharacteristic)
- assertEqual "compiled warm hit performs one exact lookup"
- [Semantic.declarationValidationRecordKey freshRecord]
- . reverse
- =<< IORef.readIORef hitLookups
- case Declaration.committedBatchDeclarationValidation hitBatch of
- Just record ->
- assertEqual
- "compiled hit republishes the exact validation"
- freshRecord
- record
- Nothing ->
- assertFailure "compiled hit omitted validation"
-
-foundationProposition
- :: Fixture
- -> Foundation.FoundationAxiomTag
- -> IO Identity.CheckedPropositionContent
-foundationProposition fixture tag = do
- closure <- expectRight
- (Identity.validateObjectClosure
- (Identity.theoryId (fixtureFoundation fixture))
- [])
- expectRight
- (Identity.validatePropositionContent
- closure
- (Core.frozenCoreTerm
- (Core.mapFrozenGlobals
- absurd
- (Foundation.foundationAxiomFrozen
- (fixtureFoundation fixture)
- tag))))
-
-opaqueFixtureObject :: Fixture -> Identity.AssertedObject
-opaqueFixtureObject fixture =
- let theory = Identity.theoryId (fixtureFoundation fixture)
- seed =
- Identity.opaqueDeclarationSeed
- (fixtureOwner fixture)
- (localDeclarationOrdinal 0)
- SignatureDeclaration
- (generatedObjectSlot 0)
- identity =
- Identity.opaqueObjectId
- theory
- seed
- Core.TySet
- in Identity.assertedObject
- identity
- (Identity.OpaqueObjectContent
- theory
- seed
- Core.TySet)
-
-datatypeFixtureObject
- :: Fixture
- -> Natural
- -> Identity.AssertedObject
-datatypeFixtureObject fixture slot =
- let theory = Identity.theoryId (fixtureFoundation fixture)
- seed =
- Identity.opaqueDeclarationSeed
- (fixtureOwner fixture)
- (localDeclarationOrdinal 0)
- DatatypeDeclaration
- (generatedObjectSlot slot)
- identity =
- Identity.opaqueObjectId theory seed Core.TySet
- in Identity.assertedObject
- identity
- (Identity.OpaqueObjectContent theory seed Core.TySet)
-
-
-data Fixture = Fixture
- { fixtureFoundation :: !Foundation.CheckedFoundation
- , fixtureOwner :: !ModuleName
- , fixtureProposition :: !Identity.CheckedPropositionContent
- }
-
-makeFixture :: IO Fixture
-makeFixture =
- makeNamedFixture "root"
-
-makeNamedFixture :: Text -> IO Fixture
-makeNamedFixture name = do
- foundation <- expectRight Foundation.checkedFoundation
- namespaceDigest <- expectRight
- (hashCanonicalFields
- "declaration-test-namespace"
- [TextEncoding.encodeUtf8 name])
- relative <- expectRight
- (safeRelativePath
- (Text.unpack name <> ".tex"))
- let theory = Identity.theoryId foundation
- owner =
- moduleNameFromParts
- (sourceNamespaceIdFromDigest namespaceDigest)
- relative
- closure <- expectRight
- (Identity.validateObjectClosure theory [])
- proposition <- expectRight
- (Identity.validatePropositionContent closure Core.CFalsum)
- pure
- Fixture
- { fixtureFoundation = foundation
- , fixtureOwner = owner
- , fixtureProposition = proposition
- }
-
-factSpec :: Fixture -> Text -> Declaration.CandidateSpec
-factSpec fixture alias =
- Declaration.candidateSpec
- (fixtureProposition fixture)
- Semantic.SearchEligible
- [Semantic.semanticName alias]
-
-runDriver
- :: Fixture
- -> Declaration.ModuleDriver failure value
- -> IO (Declaration.DriverResult failure value)
-runDriver fixture =
- runDriverWithResolver fixture unavailableVampireResolver
-
-runDriverWithResolver
- :: Fixture
- -> Declaration.VampireResolver
- -> Declaration.ModuleDriver failure value
- -> IO (Declaration.DriverResult failure value)
-runDriverWithResolver fixture resolver action = do
- result <- Declaration.runModuleDriver
- (fixtureFoundation fixture)
- (fixtureOwner fixture)
- []
- resolver
- Declaration.FreshValidation
- action
- expectRight result
-
-runDriverWithValidation
- :: Fixture
- -> Declaration.ValidationLookup
- -> Declaration.ModuleDriver failure value
- -> IO (Declaration.DriverResult failure value)
-runDriverWithValidation fixture lookup action = do
- runDriverWithValidationAndResolver
- fixture
- lookup
- unavailableVampireResolver
- action
-
-runDriverWithValidationAndResolver
- :: Fixture
- -> Declaration.ValidationLookup
- -> Declaration.VampireResolver
- -> Declaration.ModuleDriver failure value
- -> IO (Declaration.DriverResult failure value)
-runDriverWithValidationAndResolver fixture lookup resolver action = do
- result <- Declaration.runModuleDriver
- (fixtureFoundation fixture)
- (fixtureOwner fixture)
- []
- resolver
- (Declaration.WarmValidation lookup)
- action
- expectRight result
-
-proofOnlyValidationLookup
- :: (Semantic.ProofValidationKey
- -> IO (Maybe Semantic.ProofValidationRecord))
- -> Declaration.ValidationLookup
-proofOnlyValidationLookup lookupProof =
- Declaration.validationLookup
- lookupProof
- (const (pure Nothing))
-
-compiledOnlyValidationLookup
- :: (Semantic.DeclarationValidationKey
- -> IO (Maybe Semantic.DeclarationValidationRecord))
- -> Declaration.ValidationLookup
-compiledOnlyValidationLookup lookupDeclaration =
- Declaration.validationLookup
- (const (pure Nothing))
- lookupDeclaration
-
-runDriverWithDirect
- :: Fixture
- -> [Semantic.SemanticInterfaceId]
- -> Declaration.ModuleDriver failure value
- -> IO (Declaration.DriverResult failure value)
-runDriverWithDirect fixture direct action = do
- result <- Declaration.runModuleDriver
- (fixtureFoundation fixture)
- (fixtureOwner fixture)
- direct
- unavailableVampireResolver
- Declaration.FreshValidation
- action
- expectRight result
-
-unavailableVampireResolver :: Declaration.VampireResolver
-unavailableVampireResolver =
- Declaration.vampireResolver \_prepared ->
- pure
- (Left
- (Provers.ProverLaunchFailed
- "unused"
- "Vampire resolver was not expected"))
-
-runSuccessful
- :: Fixture
- -> Declaration.ModuleDriver failure value
- -> IO value
-runSuccessful fixture =
- runSuccessfulWithResolver fixture unavailableVampireResolver
-
-runSuccessfulWithResolver
- :: Fixture
- -> Declaration.VampireResolver
- -> Declaration.ModuleDriver failure value
- -> IO value
-runSuccessfulWithResolver fixture resolver action = do
- outcome <- runDriverWithResolver fixture resolver action
- case outcome of
- Declaration.DriverSucceeded value _interface _prefix _closure ->
- pure value
- Declaration.DriverFailed _failure _prefix ->
- assertFailure "unexpected driver failure" >> fail "unreachable"
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure (show failure) >> fail "unreachable"
-
-runSuccessfulWithValidation
- :: Fixture
- -> Declaration.ValidationLookup
- -> Declaration.ModuleDriver failure value
- -> IO value
-runSuccessfulWithValidation fixture lookup action = do
- outcome <- runDriverWithValidation fixture lookup action
- case outcome of
- Declaration.DriverSucceeded value _interface _prefix _closure ->
- pure value
- Declaration.DriverFailed _failure _prefix ->
- assertFailure "unexpected driver failure" >> fail "unreachable"
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure (show failure) >> fail "unreachable"
-
-materializesSealedImport :: Assertion
-materializesSealedImport = do
- fixture <- makeFixture
- producer <- runDriver fixture do
- (_value, batch) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "sealed-import-producer") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "producer-fact")
- Declaration.authorizeOmittedCandidate candidate
- Declaration.recordOmittedUse
- pure batch
- (producerInterface, evidence, fingerprint) <-
- case producer of
- Declaration.DriverSucceeded _ interface prefix _closure ->
- let imported =
- Declaration.freshImportedModuleEvidence
- [] interface prefix
- in case concatMap
- Semantic.declarationDeltaFacts
- (Semantic.semanticInterfaceDeclarations interface) of
- [occurrence] ->
- pure
- ( interface
- , imported
- , Semantic.semanticFactFingerprint occurrence
- )
- occurrences ->
- assertFailure
- ("unexpected producer facts: "
- <> show (length occurrences))
- >> fail "unreachable"
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("producer failed: "
- <> show
- (failure
- :: Declaration.DriverFailure
- Declaration.DeclarationError))
- >> fail "unreachable"
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure ("producer did not seal: " <> show failure)
- >> fail "unreachable"
- consumerNamespace <- expectRight
- (hashCanonicalFields
- "declaration-import-consumer"
- ["consumer"])
- consumerPath <- expectRight (safeRelativePath "consumer.tex")
- let consumerFixture =
- fixture
- { fixtureOwner =
- moduleNameFromParts
- (sourceNamespaceIdFromDigest consumerNamespace)
- consumerPath
- }
- consumer <- runDriverWithDirect consumerFixture
- [Semantic.semanticInterfaceAssertedId producerInterface]
- do
- (_value, committed) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "sealed-import-consumer") do
- Declaration.importSealedModule evidence
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "consumer-fact")
- Declaration.authorizeOmittedCandidate candidate do
- _ <- Declaration.useAuthorizedFact fingerprint
- Declaration.recordOmittedUse
- pure committed
- case consumer of
- Declaration.DriverSucceeded committed _ _ _ -> do
- case Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta committed) of
- [localOccurrence] -> do
- assertEqual
- "the first local fact keeps ordinal zero"
- (localFactOrdinal 0)
- (Semantic.factSlotOrdinal
- (Semantic.semanticFactSlot localOccurrence))
- assertEqual
- "the local fact belongs to the consumer"
- (fixtureOwner consumerFixture)
- (Semantic.factSlotModule
- (Semantic.semanticFactSlot localOccurrence))
- facts ->
- assertFailure
- ("unexpected consumer fact count: "
- <> show (length facts))
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("consumer failed: "
- <> show
- (failure
- :: Declaration.DriverFailure
- Declaration.DeclarationError))
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure ("consumer did not seal: " <> show failure)
-
-elaboratesScopedExactPropositions :: Assertion
-elaboratesScopedExactPropositions = do
- fixture <- makeNamedFixture "exact-scoped-proposition"
- let x = Raw.NamedVar "x"
- y = Raw.NamedVar "y"
- statement =
- Raw.SymbolicQuantified
- Nowhere
- Raw.Universally
- (x :| [y])
- Raw.Unbounded
- Nothing
- (Raw.StmtFormula
- (Raw.FormulaChain
- (Raw.ChainBase
- (Raw.ExprVar x :| [])
- Raw.Positive
- (Raw.Relation
- Nowhere
- Raw.EqSymbol
- [])
- (Raw.ExprVar y :| []))))
- action
- :: Declaration.ModuleDriver Text
- (Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition)
- action =
- Declaration.runProspectiveLoweringDriver
- (Exact.prepareExactProposition
- Exact.emptyExactBinderContext
- statement)
- outcome <- runDriver fixture action
- case outcome of
- Declaration.DriverSucceeded (Right prepared) _interface _prefix _closure ->
- assertEqual
- "source-order universal binders"
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CEq Core.TySet
- (Core.CBound 1)
- (Core.CBound 0))))
- (Core.scopedCoreTerm
- (Exact.preparedExactPropositionCore prepared))
- Declaration.DriverSucceeded (Left failure) _interface _prefix _closure ->
- assertFailure
- ("scoped exact elaboration failed: "
- <> Text.unpack (Exact.renderExactCompileError failure))
- Declaration.DriverFailed failure _prefix ->
- assertFailure ("scoped exact driver failed: " <> show failure)
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure ("scoped exact driver did not seal: " <> show failure)
-
-lowersFixedEqualityAliases :: Assertion
-lowersFixedEqualityAliases = do
- fixture <- makeNamedFixture "fixed-equality-aliases"
- let x = Raw.NamedVar "x"
- y = Raw.NamedVar "y"
- z = Raw.NamedVar "z"
- term variable = Raw.TermExpr (Raw.ExprVar variable)
- equality left right =
- Raw.StmtFormula
- (Raw.FormulaChain
- (Raw.ChainBase
- (Raw.ExprVar left :| [])
- Raw.Positive
- (Raw.Relation Nowhere Raw.EqSymbol [])
- (Raw.ExprVar right :| [])))
- quantified variables statement =
- Raw.SymbolicQuantified
- Nowhere
- Raw.Universally
- variables
- Raw.Unbounded
- Nothing
- statement
- adjective =
- Raw.Adj
- Nowhere
- Lexicon.builtinEqualityRightAdjective
- [term y]
- copular =
- Raw.StmtVerbPhrase
- (term x :| [])
- (Raw.VPAdj (adjective :| []))
- rightAttribute =
- Raw.StmtNoun
- (term x :| [])
- (Raw.NounPhrase
- []
- (Raw.Noun Nowhere Lexicon.builtinSetNoun [])
- Nothing
- [ Raw.AdjR
- Nowhere
- Lexicon.builtinEqualityRightAdjective
- [term y]
- ]
- Nothing)
- rightAttributeExpected =
- Raw.StmtNoun
- (term x :| [])
- (Raw.NounPhrase
- []
- (Raw.Noun Nowhere Lexicon.builtinSetNoun [])
- Nothing
- []
- (Just (equality x y)))
- verb argument =
- Raw.Verb
- Nowhere
- Lexicon.builtinEqualityVerb
- [term argument]
- singular =
- Raw.StmtVerbPhrase
- (term x :| [])
- (Raw.VPVerb (verb y))
- negated =
- Raw.StmtVerbPhrase
- (term x :| [])
- (Raw.VPVerbNot (verb y))
- coordinated =
- Raw.StmtVerbPhrase
- (term x :| [term y])
- (Raw.VPVerb (verb z))
- coordinatedExpected =
- Raw.StmtConnected
- Raw.Conjunction
- Nothing
- (equality x z)
- (equality y z)
- comparisons =
- [ ( "copular adjective"
- , quantified (x :| [y]) copular
- , quantified (x :| [y]) (equality x y)
- )
- , ( "right adjective"
- , quantified (x :| [y]) rightAttribute
- , quantified (x :| [y]) rightAttributeExpected
- )
- , ( "singular verb"
- , quantified (x :| [y]) singular
- , quantified (x :| [y]) (equality x y)
- )
- , ( "negated verb"
- , quantified (x :| [y]) negated
- , quantified
- (x :| [y])
- (Raw.StmtNeg Nowhere (equality x y))
- )
- , ( "quantified coordinated verb"
- , quantified (x :| [y, z]) coordinated
- , quantified (x :| [y, z]) coordinatedExpected
- )
- ]
- action
- :: Declaration.ModuleDriver Text
- [ ( Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition
- , Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition
- )
- ]
- action =
- Declaration.runProspectiveLoweringDriver
- (traverse
- (\(_label, alias, symbolic) ->
- (,)
- <$> Exact.prepareExactProposition
- Exact.emptyExactBinderContext alias
- <*> Exact.prepareExactProposition
- Exact.emptyExactBinderContext symbolic)
- comparisons)
- runDriver fixture action >>= \case
- Declaration.DriverSucceeded results _interface _prefix _closure ->
- for_ (zip comparisons results) \((label, _alias, _symbolic), result) ->
- case result of
- (Right alias, Right symbolic) -> do
- let aliasTerm =
- Core.scopedCoreTerm
- (Exact.preparedExactPropositionCore alias)
- symbolicTerm =
- Core.scopedCoreTerm
- (Exact.preparedExactPropositionCore symbolic)
- assertEqual
- (label <> " checked core")
- symbolicTerm
- aliasTerm
- assertEqual
- (label <> " global support")
- Set.empty
- (Core.canonicalTermGlobals aliasTerm)
- assertEqual
- (label <> " foundation support")
- Set.empty
- (Foundation.foundationAxiomDependencies aliasTerm)
- (Left failure, _) ->
- assertFailure
- (label <> " alias failed: "
- <> Text.unpack
- (Exact.renderExactCompileError failure))
- (_, Left failure) ->
- assertFailure
- (label <> " symbolic comparison failed: "
- <> Text.unpack
- (Exact.renderExactCompileError failure))
- Declaration.DriverFailed failure _prefix ->
- assertFailure ("fixed equality driver failed: " <> show failure)
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure ("fixed equality driver did not seal: " <> show failure)
-
- let internalEquality =
- Internal.FormulaVerb
- Nowhere
- (Internal.EmptySet Nowhere)
- Lexicon.builtinEqualityVerb
- [Internal.EmptySet Nowhere]
- internalResult
- :: Either
- Typed.TypedInductiveError
- (Core.FrozenCheckedCore Void)
- internalResult =
- Typed.prepareTypedClosedFormula
- absurd
- (const Nothing)
- internalEquality
- case internalResult of
- Right checked -> do
- assertEqual
- "internal fixed verb core"
- (Core.CEq
- Core.TySet
- (Core.CIntrinsic Core.Empty)
- (Core.CIntrinsic Core.Empty))
- (Core.frozenCoreTerm checked)
- assertEqual
- "internal fixed verb global support"
- Set.empty
- (Core.frozenCoreGlobals checked)
- Left failure ->
- assertFailure
- ("internal fixed verb failed: " <> show failure)
-
-scopesQuantifiedPropositionTerms :: Assertion
-scopesQuantifiedPropositionTerms = do
- fixture <- makeNamedFixture "quantified-proposition-terms"
- let x = Raw.NamedVar "x"
- y = Raw.NamedVar "y"
- term variable = Raw.TermExpr (Raw.ExprVar variable)
- zero = Raw.TermExpr (Raw.ExprInteger Nowhere 0)
- setNoun = Raw.Noun Nowhere Lexicon.builtinSetNoun []
- setPhrase named = Raw.NounPhrase [] setNoun named [] Nothing
- quantified quantifier variable =
- Raw.TermQuantified
- quantifier Nowhere (setPhrase (Just variable))
- equalityVerb argument =
- Raw.Verb Nowhere Lexicon.builtinEqualityVerb [argument]
- equalityAdjective argument =
- Raw.Adj
- Nowhere Lexicon.builtinEqualityRightAdjective [argument]
- equality left right = Core.CEq Core.TySet left right
- notP proposition = Core.CImp proposition Core.CFalsum
- andP left right = notP (Core.CImp left (notP right))
- existsP body = notP (Core.CForall Core.TySet (notP body))
- truth = Core.CImp Core.CFalsum Core.CFalsum
- member left right =
- Core.CApp
- (Core.CApp (Core.CIntrinsic Core.Member) left)
- right
- soleSubject =
- Raw.StmtNoun
- (quantified Raw.Universally x :| [])
- (setPhrase Nothing)
- explicitSubject =
- Raw.SymbolicQuantified
- Nowhere Raw.Universally (x :| []) Raw.Unbounded Nothing
- (Raw.StmtNoun (term x :| []) (setPhrase Nothing))
- multipleSubjects =
- Raw.StmtVerbPhrase
- ( quantified Raw.Universally x
- :| [quantified Raw.Existentially y]
- )
- (Raw.VPVerb (equalityVerb zero))
- adjectiveArgument =
- Raw.StmtVerbPhrase
- (zero :| [])
- (Raw.VPAdj
- (equalityAdjective
- (quantified Raw.Universally x) :| []))
- nounArgument =
- Raw.StmtNoun
- (zero :| [])
- (Raw.NounPhrase
- []
- (Raw.Noun
- Nowhere Lexicon.builtinElementNoun
- [quantified Raw.Universally x])
- Nothing [] Nothing)
- negatedSubject =
- Raw.StmtVerbPhrase
- (quantified Raw.Universally x :| [])
- (Raw.VPVerbNot (equalityVerb zero))
- negatedArgument =
- Raw.StmtVerbPhrase
- (zero :| [])
- (Raw.VPVerbNot
- (equalityVerb (quantified Raw.Universally x)))
- nonexistentialArgument =
- Raw.StmtVerbPhrase
- (zero :| [])
- (Raw.VPVerb
- (equalityVerb (quantified Raw.Nonexistentially x)))
- negatedStatement =
- Raw.StmtNeg Nowhere soleSubject
- siblingConstraints =
- Raw.StmtNoun
- (zero :| [])
- (Raw.NounPhrase
- []
- (Raw.Noun
- Nowhere Lexicon.builtinElementNoun
- [quantified Raw.Universally x])
- Nothing
- [Raw.AdjR
- Nowhere Lexicon.builtinEqualityRightAdjective
- [quantified Raw.Universally y]]
- Nothing)
- constrainedSubject =
- Raw.TermQuantified Raw.Universally Nowhere
- (Raw.NounPhrase
- []
- (Raw.Noun
- Nowhere Lexicon.builtinElementNoun [term x])
- (Just x)
- [Raw.AdjR
- Nowhere Lexicon.builtinEqualityRightAdjective [term x]]
- (Just
- (Raw.StmtVerbPhrase
- (term x :| [])
- (Raw.VPVerb (equalityVerb (term x))))))
- constrainedStatement =
- Raw.StmtVerbPhrase
- (constrainedSubject :| [])
- (Raw.VPVerb (equalityVerb (term x)))
- xEqualsX = equality (Core.CBound 0) (Core.CBound 0)
- cases =
- [ ( "sole quantified subject"
- , soleSubject
- , Core.CForall Core.TySet truth
- )
- , ( "explicit sole quantified subject"
- , explicitSubject
- , Core.CForall Core.TySet truth
- )
- , ( "multiple quantified subjects"
- , multipleSubjects
- , Core.CForall Core.TySet
- (existsP
- (andP
- (equality
- (Core.CBound 1) (Core.COpaqueInteger 0))
- (equality
- (Core.CBound 0) (Core.COpaqueInteger 0))))
- )
- , ( "quantified adjective argument"
- , adjectiveArgument
- , Core.CForall Core.TySet
- (equality (Core.COpaqueInteger 0) (Core.CBound 0))
- )
- , ( "quantified noun argument"
- , nounArgument
- , Core.CForall Core.TySet
- (member (Core.COpaqueInteger 0) (Core.CBound 0))
- )
- , ( "quantified subject outside negation"
- , negatedSubject
- , Core.CForall Core.TySet
- (notP
- (equality
- (Core.CBound 0) (Core.COpaqueInteger 0)))
- )
- , ( "quantified argument inside negation"
- , negatedArgument
- , notP
- (Core.CForall Core.TySet
- (equality
- (Core.COpaqueInteger 0) (Core.CBound 0)))
- )
- , ( "nonexistential quantified verb argument"
- , nonexistentialArgument
- , notP
- (existsP
- (equality
- (Core.COpaqueInteger 0)
- (Core.CBound 0)))
- )
- , ( "statement recursion bounds a quantified subject"
- , negatedStatement
- , notP (Core.CForall Core.TySet truth)
- )
- , ( "sibling constraints own their argument quantifiers"
- , siblingConstraints
- , andP
- (Core.CForall Core.TySet
- (member
- (Core.COpaqueInteger 0)
- (Core.CBound 0)))
- (Core.CForall Core.TySet
- (equality
- (Core.COpaqueInteger 0)
- (Core.CBound 0)))
- )
- , ( "quantified noun constraints share their binder"
- , constrainedStatement
- , Core.CForall Core.TySet
- (Core.CImp
- (andP
- (member (Core.CBound 0) (Core.CBound 0))
- (andP xEqualsX xEqualsX))
- xEqualsX)
- )
- ]
- prepare context statement =
- Exact.prepareExactProposition context statement
- activeContext <- expectRight
- (Exact.extendExactBinderContext
- ((Exact.exactLocalId 0, x) :| [])
- Exact.emptyExactBinderContext)
- let action
- :: Declaration.ModuleDriver Text
- ( [ Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition
- ]
- , Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition
- )
- action =
- Declaration.runProspectiveLoweringDriver do
- compiled <- traverse
- (\(_label, statement, _expected) ->
- prepare Exact.emptyExactBinderContext statement)
- cases
- collision <- prepare activeContext soleSubject
- pure (compiled, collision)
- runDriver fixture action >>= \case
- Declaration.DriverSucceeded
- (compiled, collision) _interface _prefix _closure -> do
- for_ (zip cases compiled) \
- ((label, _statement, expected), result) ->
- case result of
- Right prepared ->
- assertEqual label expected
- (Core.scopedCoreTerm
- (Exact.preparedExactPropositionCore prepared))
- Left failure ->
- assertFailure
- (label <> " failed: "
- <> Text.unpack
- (Exact.renderExactCompileError failure))
- case collision of
- Left (Exact.ExactDuplicateLocalBinder _location variable) ->
- assertEqual "quantified binder collision" x variable
- Left failure ->
- assertFailure
- ("unexpected quantified-binder collision: "
- <> Text.unpack
- (Exact.renderExactCompileError failure))
- Right{} ->
- assertFailure "an active quantified binder was shadowed"
- case compiled of
- Right sole : Right explicit : _ ->
- assertEqual
- "sole-subject lowering remains byte-for-byte identical"
- (Exact.preparedExactPropositionCore sole)
- (Exact.preparedExactPropositionCore explicit)
- _ ->
- assertFailure
- "sole-subject equality comparison did not compile"
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("quantified proposition-term driver failed: " <> show failure)
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure
- ("quantified proposition-term driver did not seal: "
- <> show failure)
-
-preparesExactClaimEnvelopes :: Assertion
-preparesExactClaimEnvelopes = do
- fixture <- makeNamedFixture "exact-claim-envelope"
- let bLocation = mkLocation (FileId 78) 2 11
- aLocation = mkLocation (FileId 78) 2 15
- xLocation = mkLocation (FileId 78) 3 9
- b = Raw.NamedVarAt bLocation "b"
- a = Raw.NamedVarAt aLocation "a"
- x = Raw.NamedVarAt xLocation "x"
- c = Raw.NamedVarAt Nowhere "c"
- d = Raw.NamedVarAt Nowhere "d"
- z = Raw.NamedVarAt Nowhere "z"
- equality left right =
- Raw.StmtFormula
- (Raw.FormulaChain
- (Raw.ChainBase
- (Raw.ExprVar left :| [])
- Raw.Positive
- (Raw.Relation Nowhere Raw.EqSymbol [])
- (Raw.ExprVar right :| [])))
- quantified variable body =
- Raw.SymbolicQuantified
- (locate variable)
- Raw.Universally
- (variable :| [])
- Raw.Unbounded
- Nothing
- body
- sourceAssumptions = [Raw.AsmSuppose (equality b a)]
- sourceConclusion = quantified x (equality x b)
- alphaAssumptions = [Raw.AsmSuppose (equality c d)]
- alphaConclusion = quantified z (equality z c)
- action
- :: Declaration.ModuleDriver Text
- ( Either
- Exact.ExactCompileError
- Exact.PreparedExactClaimEnvelope
- , Either
- Exact.ExactCompileError
- Exact.PreparedExactClaimEnvelope
- )
- action =
- Declaration.runProspectiveLoweringDriver do
- source <- Exact.prepareExactClaimEnvelope
- sourceAssumptions sourceConclusion
- alpha <- Exact.prepareExactClaimEnvelope
- alphaAssumptions alphaConclusion
- pure (source, alpha)
- expected =
- Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CImp
- (Core.CEq Core.TySet
- (Core.CBound 1)
- (Core.CBound 0))
- (Core.CForall Core.TySet
- (Core.CEq Core.TySet
- (Core.CBound 0)
- (Core.CBound 2)))))
- runDriver fixture action >>= \case
- Declaration.DriverSucceeded
- (Right source, Right alpha)
- _interface _prefix _closure -> do
- let sourceTarget = Exact.preparedExactClaimTarget source
- alphaTarget = Exact.preparedExactClaimTarget alpha
- assertEqual "closed claim envelope core"
- expected
- (Core.scopedCoreTerm sourceTarget)
- assertEqual "claim envelope is closed"
- []
- (Core.scopedCoreContext sourceTarget)
- assertEqual "first semantic occurrence binder order"
- [bLocation, aLocation]
- (locate <$> Exact.preparedExactClaimVariables source)
- assertEqual "explicit binders are not generalized"
- 2
- (length (Exact.preparedExactClaimVariables source))
- assertEqual "header antecedent count"
- 1
- (Exact.preparedExactClaimAntecedentCount source)
- assertEqual "alpha-renaming preserves the checked target"
- sourceTarget alphaTarget
- assertEqual "alpha-renaming preserves proposition identity"
- (Identity.propositionIdOf
- (Core.scopedCoreTerm sourceTarget))
- (Identity.propositionIdOf
- (Core.scopedCoreTerm alphaTarget))
- Declaration.DriverSucceeded result _interface _prefix _closure ->
- assertFailure
- ("exact claim envelope preparation failed: "
- <> case result of
- (Left failure, _) ->
- Text.unpack
- (Exact.renderExactCompileError failure)
- (_, Left failure) ->
- Text.unpack
- (Exact.renderExactCompileError failure))
- Declaration.DriverFailed failure _prefix ->
- assertFailure ("claim envelope driver failed: " <> show failure)
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure
- ("claim envelope driver did not seal: " <> show failure)
-
-lowersExactSeparationComprehensions :: Assertion
-lowersExactSeparationComprehensions = do
- fixture <- makeNamedFixture "exact-separation-comprehension"
- let binderLocation = mkLocation (FileId 73) 2 7
- ambientLocation = mkLocation (FileId 73) 2 18
- boundOccurrenceLocation = mkLocation (FileId 73) 3 14
- x = Raw.NamedVarAt binderLocation "x"
- a = Raw.NamedVarAt ambientLocation "A"
- equality left right =
- Raw.StmtFormula
- (Raw.FormulaChain
- (Raw.ChainBase
- (left :| [])
- Raw.Positive
- (Raw.Relation Nowhere Raw.EqSymbol [])
- (right :| [])))
- separation bound =
- Raw.ExprSep
- binderLocation
- x
- bound
- (equality (Raw.ExprVar x) (Raw.ExprVar a))
- validStatement =
- Raw.SymbolicQuantified
- Nowhere
- Raw.Universally
- (a :| [])
- Raw.Unbounded
- Nothing
- (equality
- (separation (Raw.ExprVar a))
- (Raw.ExprVar a))
- boundOccurrence =
- Raw.NamedVarAt boundOccurrenceLocation "x"
- invalidStatement =
- equality
- (separation (Raw.ExprVar boundOccurrence))
- (Raw.ExprVar a)
- action
- :: Declaration.ModuleDriver Text
- ( Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition
- , Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition
- )
- action =
- Declaration.runProspectiveLoweringDriver do
- valid <- Exact.prepareExactProposition
- Exact.emptyExactBinderContext
- validStatement
- invalid <- Exact.prepareExactProposition
- Exact.emptyExactBinderContext
- invalidStatement
- pure (valid, invalid)
- outcome <- runDriver fixture action
- case outcome of
- Declaration.DriverSucceeded
- (Right prepared, Left failure) _interface _prefix _closure -> do
- assertEqual
- "separation comprehension core"
- (Core.CForall Core.TySet
- (Core.CEq Core.TySet
- (Core.CApp
- (Core.CApp
- (Core.CIntrinsic Core.Sep)
- (Core.CBound 0))
- (Core.CLam Core.TySet
- (Core.CEq Core.TySet
- (Core.CBound 0)
- (Core.CBound 1))))
- (Core.CBound 0)))
- (Core.scopedCoreTerm
- (Exact.preparedExactPropositionCore prepared))
- assertEqual
- "separation proposition type"
- Core.TyProp
- (Core.scopedCoreType
- (Exact.preparedExactPropositionCore prepared))
- assertEqual
- "the separation binder is unavailable in its bound"
- (Exact.ExactFreeVariable
- boundOccurrenceLocation
- boundOccurrence)
- failure
- Declaration.DriverSucceeded result _interface _prefix _closure ->
- case result of
- (Left validFailure, _) ->
- assertFailure
- ("valid separation failed: "
- <> Text.unpack
- (Exact.renderExactCompileError validFailure))
- (_, Right{}) ->
- assertFailure "invalid separation was accepted"
- Declaration.DriverFailed failure _prefix ->
- assertFailure ("separation exact driver failed: " <> show failure)
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure ("separation exact driver did not seal: " <> show failure)
-
-lowersExactReplacementTelescopes :: Assertion
-lowersExactReplacementTelescopes = do
- fixture <- makeNamedFixture "exact-replacement-telescope"
- let location = mkLocation (FileId 74) 2 1
- futureOccurrenceLocation = mkLocation (FileId 74) 7 19
- a = Raw.NamedVarAt location "A"
- x = Raw.NamedVarAt location "x"
- y = Raw.NamedVarAt location "y"
- futureY = Raw.NamedVarAt futureOccurrenceLocation "y"
- equality left right =
- Raw.StmtFormula
- (Raw.FormulaChain
- (Raw.ChainBase
- (left :| [])
- Raw.Positive
- (Raw.Relation Nowhere Raw.EqSymbol [])
- (right :| [])))
- replacement firstDomain =
- Raw.ExprReplace
- location
- (Raw.ExprVar y)
- ( (x, firstDomain) :|
- [(y, Raw.ExprVar x)]
- )
- (Just (equality (Raw.ExprVar x) (Raw.ExprVar y)))
- validStatement =
- Raw.SymbolicQuantified
- Nowhere
- Raw.Universally
- (a :| [])
- Raw.Unbounded
- Nothing
- (equality
- (replacement (Raw.ExprVar a))
- (Raw.ExprVar a))
- invalidStatement =
- equality
- (replacement (Raw.ExprVar futureY))
- (Raw.ExprInteger Nowhere 0)
- predicateReplacementLocation = mkLocation (FileId 74) 9 3
- predicateReplacementStatement =
- equality
- (Raw.ExprReplacePred
- predicateReplacementLocation
- y
- x
- (Raw.ExprInteger Nowhere 0)
- (equality (Raw.ExprVar x) (Raw.ExprVar y)))
- (Raw.ExprInteger Nowhere 0)
- namedPredicateReplacement =
- Raw.ExprReplacePred
- predicateReplacementLocation
- y
- x
- (Raw.ExprVar a)
- (equality (Raw.ExprVar x) (Raw.ExprVar y))
- app1 intrinsic argument =
- Core.CApp (Core.CIntrinsic intrinsic) argument
- app2 intrinsic first second =
- Core.CApp (app1 intrinsic first) second
- expected =
- Core.CForall Core.TySet $
- Core.CEq Core.TySet
- (app1 Core.FamilyUnion $
- app2 Core.Repl (Core.CBound 0) $
- Core.CLam Core.TySet $
- app2 Core.Repl
- (app2 Core.Sep
- (Core.CBound 0)
- (Core.CLam Core.TySet $
- Core.CEq Core.TySet
- (Core.CBound 1)
- (Core.CBound 0)))
- (Core.CLam Core.TySet
- (Core.CBound 0)))
- (Core.CBound 0)
- action
- :: Declaration.ModuleDriver Text
- ( Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition
- , Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition
- , Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition
- , Either
- Exact.ExactCompileError
- Exact.PreparedExactSetExpression
- )
- action =
- Declaration.runProspectiveLoweringDriver do
- valid <- Exact.prepareExactProposition
- Exact.emptyExactBinderContext
- validStatement
- invalid <- Exact.prepareExactProposition
- Exact.emptyExactBinderContext
- invalidStatement
- predicateReplacement <- Exact.prepareExactProposition
- Exact.emptyExactBinderContext
- predicateReplacementStatement
- namedContext <-
- either
- (impossible
- . Text.unpack
- . Exact.renderExactCompileError)
- pure
- (Exact.extendExactBinderContext
- ((Exact.exactLocalId 0, a) :| [])
- Exact.emptyExactBinderContext)
- named <- Exact.prepareExactSetExpression
- namedContext namedPredicateReplacement
- pure (valid, invalid, predicateReplacement, named)
- runDriver fixture action >>= \case
- Declaration.DriverSucceeded
- ( Right prepared
- , Left failure
- , Left predicateReplacementFailure
- , Right named
- ) _interface _prefix _closure -> do
- assertEqual
- "dependent replacement core"
- expected
- (Core.scopedCoreTerm
- (Exact.preparedExactPropositionCore prepared))
- assertEqual
- "future replacement binder location"
- (Exact.ExactFreeVariable futureOccurrenceLocation futureY)
- failure
- assertEqual
- "predicate replacement remains unsupported at its location"
- (Exact.ExactRelationalReplacementRequiresNamedDefinition
- predicateReplacementLocation)
- predicateReplacementFailure
- case Exact.preparedExactSetExpressionConstruction named of
- Just (Exact.PreparedRelationalSetConstruction construction) -> do
- assertEqual "relational replacement canonical term"
- expectedRelationalTerm
- (Core.scopedCoreTerm
- (SetConstruction.relationalSetConstructionTerm
- construction))
- assertEqual "relational replacement functionality"
- expectedFunctionality
- (Core.scopedCoreTerm
- (SetConstruction.relationalSetConstructionFunctionality
- construction))
- let relationalObject =
- Identity.assertedObjectId
- (opaqueFixtureObject fixture)
- closedFunctionality =
- SetConstruction.relationalSetConstructionClosedFunctionality
- construction
- relationalFact <-
- maybe
- (assertFailure
- "exact functionality did not unlock relational extensionality"
- >> fail "unreachable")
- pure
- (SetConstruction.relationalSetConstructionObjectFact
- (SetConstruction.checkedFoundationSetConstruction
- (fixtureFoundation fixture))
- relationalObject
- construction
- closedFunctionality)
- assertEqual
- "relational replacement flattened extensional proposition"
- (expectedRelationalExtensional relationalObject)
- (Core.frozenCoreTerm
- (SetConstruction.relationalSetConstructionFactProposition
- relationalFact))
- assertEqual
- "unrelated functionality cannot unlock the relational view"
- Nothing
- (SetConstruction.relationalSetConstructionLocalViews
- (SetConstruction.checkedFoundationSetConstruction
- (fixtureFoundation fixture))
- construction
- (Core.falsumScopedCore [Core.TySet]))
- wrongClosed <- expectRight
- (Core.checkCanonicalCore
- (const Nothing)
- Core.CFalsum)
- assertBool
- "malformed relational authority is rejected"
- (isNothing
- (SetConstruction.relationalSetConstructionObjectFact
- (SetConstruction.checkedFoundationSetConstruction
- (fixtureFoundation fixture))
- relationalObject
- construction
- wrongClosed))
- _ ->
- assertFailure
- "named predicate replacement lost its relational construction"
- Declaration.DriverSucceeded
- (Left validFailure, _, _, _) _interface _prefix _closure ->
- assertFailure
- ("valid replacement failed: "
- <> Text.unpack
- (Exact.renderExactCompileError validFailure))
- Declaration.DriverSucceeded
- (_, Right{}, _, _) _interface _prefix _closure ->
- assertFailure "invalid replacement was accepted"
- Declaration.DriverSucceeded
- (_, _, Right{}, _) _interface _prefix _closure ->
- assertFailure "predicate replacement was accepted"
- Declaration.DriverSucceeded
- (_, _, _, Left failure) _interface _prefix _closure ->
- assertFailure
- ("named predicate replacement failed: "
- <> Text.unpack (Exact.renderExactCompileError failure))
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("replacement driver failed: " <> show failure)
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure
- ("replacement driver did not seal: " <> show failure)
- where
- relApp1 intrinsic argument =
- Core.CApp (Core.CIntrinsic intrinsic) argument
- relApp2 intrinsic first second =
- Core.CApp (relApp1 intrinsic first) second
- notP proposition = Core.CImp proposition Core.CFalsum
- andP left right = notP (Core.CImp left (notP right))
- existsP body = notP (Core.CForall Core.TySet (notP body))
- relation = Core.CEq Core.TySet (Core.CBound 1) (Core.CBound 0)
- restricted =
- relApp2 Core.Sep (Core.CBound 0)
- (Core.CLam Core.TySet (existsP relation))
- expectedRelationalTerm =
- relApp2 Core.Repl restricted
- (Core.CLam Core.TySet
- (relApp1 Core.SetChoose (Core.CLam Core.TySet relation)))
- expectedFunctionality =
- Core.CForall Core.TySet
- (Core.CImp
- (relApp2 Core.Member (Core.CBound 0) (Core.CBound 1))
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CImp
- (andP
- (Core.CEq Core.TySet
- (Core.CBound 2) (Core.CBound 1))
- (Core.CEq Core.TySet
- (Core.CBound 2) (Core.CBound 0)))
- (Core.CEq Core.TySet
- (Core.CBound 1) (Core.CBound 0))))))
- expectedRelationalExtensional object =
- Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CEq Core.TyProp
- (relApp2 Core.Member
- (Core.CBound 0)
- (Core.CApp
- (Core.CGlobal object)
- (Core.CBound 1)))
- (existsP
- (andP
- (relApp2 Core.Member
- (Core.CBound 0)
- (Core.CBound 2))
- (Core.CEq Core.TySet
- (Core.CBound 0)
- (Core.CBound 1))))))
-
-lowersExactFiniteSets :: Assertion
-lowersExactFiniteSets = do
- fixture <- makeNamedFixture "exact-finite-set"
- let location = mkLocation (FileId 75) 2 1
- a = Raw.NamedVarAt location "a"
- b = Raw.NamedVarAt location "b"
- equality left right =
- Raw.StmtFormula
- (Raw.FormulaChain
- (Raw.ChainBase
- (left :| [])
- Raw.Positive
- (Raw.Relation Nowhere Raw.EqSymbol [])
- (right :| [])))
- statement =
- Raw.SymbolicQuantified
- Nowhere
- Raw.Universally
- (a :| [b])
- Raw.Unbounded
- Nothing
- (equality
- (Raw.ExprFiniteSet
- location
- (Raw.ExprVar a :| [Raw.ExprVar b]))
- (Raw.ExprVar a))
- app1 intrinsic argument =
- Core.CApp (Core.CIntrinsic intrinsic) argument
- app2 intrinsic first second =
- Core.CApp (app1 intrinsic first) second
- insert element rest =
- app1 Core.FamilyUnion
- (app2 Core.PairSet
- (app2 Core.PairSet element element)
- rest)
- expected =
- Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CEq Core.TySet
- (insert
- (Core.CBound 1)
- (insert
- (Core.CBound 0)
- (Core.CIntrinsic Core.Empty)))
- (Core.CBound 1)))
- action
- :: Declaration.ModuleDriver Text
- (Either
- Exact.ExactCompileError
- Exact.PreparedExactProposition)
- action =
- Declaration.runProspectiveLoweringDriver
- (Exact.prepareExactProposition
- Exact.emptyExactBinderContext
- statement)
- internal <-
- expectRight
- (evalState
- (runExceptT (Meaning.glossStmt statement))
- Meaning.initialGlossState)
- reusable <-
- expectRight
- (Typed.prepareTypedClosedFormula
- absurd
- (const Nothing)
- internal
- :: Either
- Typed.TypedInductiveError
- (Core.FrozenCheckedCore Void))
- assertEqual
- "raw and reusable finite-set lowering"
- expected
- (Core.frozenCoreTerm reusable)
- let internalSymbols = Internal.mentionedSymbols internal
- assertBool
- "finite-set meaning has no source-owned cons dependency"
- (Internal.SymbolMixfix Raw.ConsSymbol
- `Set.notMember` internalSymbols)
- assertBool
- "finite-set meaning retains fixed adjunction operations"
- ( Set.fromList
- [ Internal.SymbolMixfix Raw.UnionsSymbol
- , Internal.SymbolMixfix Raw.UpairSymbol
- ]
- `Set.isSubsetOf` internalSymbols
- )
- case Vocabulary.classifyExactSymbol
- (Internal.SymbolMixfix Raw.ConsSymbol) of
- Vocabulary.ExactSourceGlobal{} -> pure ()
- classification ->
- assertFailure
- ("explicit cons did not retain source ownership: "
- <> show classification)
- runDriver fixture action >>= \case
- Declaration.DriverSucceeded
- (Right prepared) _interface _prefix _closure ->
- assertEqual
- "source-order finite-set core"
- expected
- (Core.scopedCoreTerm
- (Exact.preparedExactPropositionCore prepared))
- Declaration.DriverSucceeded
- (Left failure) _interface _prefix _closure ->
- assertFailure
- ("valid finite set failed: "
- <> Text.unpack
- (Exact.renderExactCompileError failure))
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("finite-set driver failed: " <> show failure)
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure
- ("finite-set driver did not seal: " <> show failure)
-
-lowersExactOrdinaryDeclarations :: Assertion
-lowersExactOrdinaryDeclarations = do
- fixture <- makeNamedFixture "exact-lowering"
- level <- expectRight (Syntax.mixfixLevel 2)
- let makeSymbol command marker =
- Raw.mkMixfixItem
- [ Just (Raw.Command command)
- , Just Raw.InvisibleBraceL
- , Nothing
- , Just Raw.InvisibleBraceR
- ]
- (Raw.Marker marker)
- Raw.NonAssoc
- opaqueSymbol = makeSymbol "phasefiveopaque" "opaque-label"
- aliasSymbol = makeSymbol "phasefivealias" "alias-label"
- definitionSymbol = makeSymbol "phasefivedef" "definition-label"
- entry symbol =
- Syntax.CanonicalExpressionFunction
- (Raw.mixfixPattern symbol)
- (Raw.mixfixMarker symbol)
- (Syntax.Fixity Raw.NonAssoc level)
- parameter = Raw.NamedVar "x"
- exactSet =
- Raw.NounPhrase
- []
- (Raw.Noun Nowhere Lexicon.builtinSetNoun [])
- Nothing
- []
- Nothing
- signature =
- Raw.BlockSig
- Nowhere Nothing (Raw.Marker "opaque-declaration") []
- (Raw.SignatureSymbolic
- (Raw.SymbolPattern opaqueSymbol [parameter])
- exactSet)
- application symbol =
- Raw.ExprOp Nowhere symbol [Raw.ExprVar parameter]
- abbreviation =
- Raw.BlockAbbr
- Nowhere Nothing (Raw.Marker "alias-declaration")
- (Raw.AbbreviationEq
- (Raw.SymbolPattern aliasSymbol [parameter])
- (application opaqueSymbol))
- definition =
- Raw.BlockDefn
- Nowhere Nothing (Raw.Marker "definition-declaration")
- (Raw.DefnOp
- (Raw.SymbolPattern definitionSymbol [parameter])
- (application aliasSymbol))
- compile block lexicalEntry = do
- Declaration.runProspectiveLoweringDriver
- (Exact.prepareExactDeclaration block [lexicalEntry]) >>= \case
- Left failure ->
- Declaration.failModuleDriver
- (Exact.renderExactCompileError failure)
- Right prepared -> pure prepared
- admit prepared = do
- lowered <-
- Declaration.runProspectiveLoweringDriver
- (Exact.lowerPreparedExactBinding prepared)
- checked <-
- either Declaration.failDeclarationDriver pure lowered
- void
- (Declaration.admitCheckedDeclaration
- checked
- Exact.authorizeCheckedExactBinding)
- outcome <- runFixtureDriver fixture [] do
- preparedSignature <-
- compile signature (entry opaqueSymbol)
- admit preparedSignature
- preparedAbbreviation <-
- compile abbreviation (entry aliasSymbol)
- admit preparedAbbreviation
- preparedDefinition <-
- compile definition (entry definitionSymbol)
- admit preparedDefinition
- pure
- ( preparedSignature
- , preparedAbbreviation
- , preparedDefinition
- )
- case outcome of
- Declaration.DriverSucceeded
- (preparedSignature, preparedAbbreviation, preparedDefinition)
- interface prefix _closure -> do
- assertEqual "three committed declarations"
- 3
- (length (Semantic.semanticInterfaceDeclarations interface))
- assertEqual "three committed batches"
- 3
- (length (Declaration.pendingModulePrefixBatches prefix))
- assertEqual "opaque signature family"
- Identity.OpaqueObject
- (Identity.objectIdFamily
- (Exact.preparedExactObjectId preparedSignature))
- assertEqual "transparent abbreviation family"
- Identity.TransparentObject
- (Identity.objectIdFamily
- (Exact.preparedExactObjectId preparedAbbreviation))
- assertEqual "transparent definition family"
- Identity.TransparentObject
- (Identity.objectIdFamily
- (Exact.preparedExactObjectId preparedDefinition))
- assertEqual "expanded definition coalesces with abbreviation"
- (Exact.preparedExactObjectId preparedAbbreviation)
- (Exact.preparedExactObjectId preparedDefinition)
- case Exact.preparedExactObject preparedAbbreviation of
- Just object ->
- case Identity.assertedObjectContent object of
- Identity.TransparentObjectContent
- _theory coreType body -> do
- assertEqual "definition type"
- (Core.TyArrow Core.TySet Core.TySet)
- coreType
- assertEqual "expanded body retains opaque seed"
- (Core.CLam Core.TySet
- (Core.CApp
- (Core.CGlobal
- (Exact.preparedExactObjectId
- preparedSignature))
- (Core.CBound 0)))
- body
- content ->
- assertFailure
- ("unexpected definition content: " <> show content)
- Nothing ->
- assertFailure "new abbreviation object was not prepared"
- assertEqual "coalesced definition adds no object"
- Nothing
- (Exact.preparedExactObject preparedDefinition)
- case reverse (Declaration.pendingModulePrefixBatches prefix) of
- definitionBatch : _ -> do
- case Declaration.committedBatchDeclarationValidation
- definitionBatch of
- Just record ->
- case Semantic.declarationValidationRecordCertificates
- record of
- [certificate] -> do
- assertEqual "definition authority"
- (Authority.CheckedKernelConstruction
- (Authority.CheckedDefinitionEquation
- (Exact.preparedExactObjectId
- preparedDefinition)))
- (Authority.validationDirectAuthorization
- certificate)
- assertEqual "definition authority is clean"
- Authority.cleanAuthoritySafety
- (Authority.factAuthoritySafety
- (Authority.validationTarget
- certificate))
- certificates ->
- assertFailure
- ("unexpected definition certificate count: "
- <> show (length certificates))
- Nothing ->
- assertFailure "definition has no declaration validation"
- [] -> assertFailure "definition batch is absent"
- Declaration.DriverFailed failure _prefix ->
- assertFailure ("exact lowering failed: " <> show failure)
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure ("exact lowering did not seal: " <> show failure)
-
- let theory = Identity.theoryId (fixtureFoundation fixture)
- mismatchBody = Core.COpaqueInteger 0
- mismatchType = Core.TySet
- mismatchId =
- Identity.transparentObjectId theory mismatchType mismatchBody
- mismatchObject =
- Identity.assertedObject
- mismatchId
- (Identity.TransparentObjectContent
- theory mismatchType mismatchBody)
- let mismatchAction
- :: Declaration.ModuleDriver Text
- ((), Declaration.CommittedDeclarationBatch)
- mismatchAction =
- Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId
- "mismatched-definition-equation") do
- Declaration.addDeclarationObject mismatchObject
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "not-a-definition-equation")
- Declaration.authorizeCompiledDeclaration
- (Declaration.authorizeDefinitionEquationCandidate
- mismatchId
- candidate)
- mismatch <- runDriver fixture mismatchAction
- case mismatch of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- Declaration.DefinitionEquationCandidateMismatch)
- prefix ->
- assertEqual "mismatched equation publishes no batch"
- 0
- (length (Declaration.pendingModulePrefixBatches prefix))
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("unexpected mismatched-equation failure: " <> show failure)
- Declaration.DriverSucceeded{} ->
- assertFailure "mismatched definition equation was authorized"
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure
- ("mismatched definition equation reached sealing: "
- <> show failure)
-
-reconstructsImportedGlobalBindings :: Assertion
-reconstructsImportedGlobalBindings = do
- producerFixture <- makeNamedFixture "global-producer"
- consumerFixture <- makeNamedFixture "global-consumer"
- conflictFixture <- makeNamedFixture "global-conflict"
- rootFixture <- makeNamedFixture "global-root"
- let key =
- Semantic.SemanticExpressionFunction
- (Raw.TokenCons (Raw.Command "phasefive") Raw.End)
- asserted = opaqueFixtureObject producerFixture
- target = Identity.assertedObjectId asserted
- publishWith targetMode fixture object = do
- (batch, sealed) <- sealFixture fixture [] do
- (_value, committed) <-
- Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId "global-binding") do
- Declaration.addDeclarationObject object
- Declaration.stageSemanticGlobalBinding
- key
- (targetMode
- (Identity.assertedObjectId object))
- Declaration.authorizeCompiledDeclaration (pure ())
- pure committed
- pure (batch, sealed)
- (producerBatch, freshProducer) <-
- publishWith Semantic.GlobalReference producerFixture asserted
- let FixtureSealed producerInterface _freshEvidence = freshProducer
- objects = Declaration.committedBatchObjects producerBatch
- cachedEvidence <- expectRight
- (Declaration.validateImportedModuleEvidence
- (Identity.theoryId
- (fixtureFoundation producerFixture))
- []
- producerInterface
- objects
- [])
- let cachedProducer = FixtureSealed producerInterface cachedEvidence
- resolveThrough label parent = do
- outcome <- runFixtureDriver consumerFixture [parent] do
- fst <$> Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId
- (TextEncoding.encodeUtf8 (Text.pack label))) do
- found <- Declaration.resolveVisibleGlobal key
- Declaration.authorizeCompiledDeclaration (pure ())
- pure found
- case outcome of
- Declaration.DriverSucceeded found _interface _prefix _closure ->
- assertEqual label
- (Just
- ( Semantic.GlobalReference target
- , Core.TySet
- ))
- found
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("global binding consumer failed: " <> show failure)
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure
- ("global binding consumer did not seal: " <> show failure)
- resolveThrough "fresh-global-binding" freshProducer
- resolveThrough "cached-global-binding" cachedProducer
-
- missingEnvironment <- expectRight
- (Semantic.semanticEnvironmentDelta
- [Semantic.semanticGlobalBinding
- key
- (Semantic.GlobalReference target)])
- missingDelta <- expectRight
- (Semantic.declarationInterfaceDelta
- (Semantic.declarationSlot
- (fixtureOwner producerFixture)
- (localDeclarationOrdinal 0))
- []
- []
- []
- []
- missingEnvironment)
- missingInterface <- expectRight
- (Semantic.semanticInterface
- (fixtureOwner producerFixture)
- []
- [missingDelta])
- case Declaration.validateImportedModuleEvidence
- (Identity.theoryId
- (fixtureFoundation producerFixture))
- []
- missingInterface
- []
- [] of
- Left (Declaration.ImportedGlobalTargetInvalid
- actualKey actualTarget
- (Semantic.SemanticGlobalTargetMissing missingTarget)) -> do
- assertEqual "missing target key" key actualKey
- assertEqual "missing target mode"
- (Semantic.GlobalReference target)
- actualTarget
- assertEqual "missing target object" target missingTarget
- Left failure ->
- assertFailure
- ("unexpected missing-target failure: " <> show failure)
- Right _evidence ->
- assertFailure "cached evidence accepted a missing target object"
-
- expansionEnvironment <- expectRight
- (Semantic.semanticEnvironmentDelta
- [Semantic.semanticGlobalBinding
- key
- (Semantic.TransparentExpansion target)])
- expansionDelta <- expectRight
- (Semantic.declarationInterfaceDelta
- (Semantic.declarationSlot
- (fixtureOwner producerFixture)
- (localDeclarationOrdinal 0))
- [] [] [target] [] expansionEnvironment)
- expansionInterface <- expectRight
- (Semantic.semanticInterface
- (fixtureOwner producerFixture) [] [expansionDelta])
- case Declaration.validateImportedModuleEvidence
- (Identity.theoryId
- (fixtureFoundation producerFixture))
- []
- expansionInterface
- [asserted]
- [] of
- Left (Declaration.ImportedGlobalTargetInvalid
- actualKey actualTarget
- (Semantic.SemanticGlobalExpansionNotTransparent
- invalidTarget)) -> do
- assertEqual "nontransparent target key" key actualKey
- assertEqual "nontransparent target mode"
- (Semantic.TransparentExpansion target)
- actualTarget
- assertEqual "nontransparent target object" target invalidTarget
- Left failure ->
- assertFailure
- ("unexpected nontransparent-target failure: "
- <> show failure)
- Right _evidence ->
- assertFailure "cached evidence accepted a nontransparent expansion"
-
- let intrinsicTarget =
- Identity.intrinsicObjectId
- (Identity.theoryId
- (fixtureFoundation producerFixture))
- Core.Empty
- Core.TySet
- intrinsicObject =
- Identity.assertedObject
- intrinsicTarget
- (Identity.IntrinsicObjectContent
- (Identity.theoryId
- (fixtureFoundation producerFixture))
- Core.Empty
- Core.TySet)
- intrinsicFailure <- runFixtureDriver producerFixture [] do
- Declaration.commitCompiledDeclaration
- (Semantic.declarationSyntaxId "intrinsic-global-binding") do
- Declaration.addDeclarationObject intrinsicObject
- Declaration.stageSemanticGlobalBinding
- key
- (Semantic.GlobalReference intrinsicTarget)
- Declaration.authorizeCompiledDeclaration (pure ())
- case intrinsicFailure of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- (Declaration.DeclarationGlobalTargetInvalid
- actualKey actualTarget
- (Semantic.SemanticGlobalTargetIsIntrinsic
- invalidTarget)))
- _prefix -> do
- assertEqual "intrinsic target key" key actualKey
- assertEqual "intrinsic target mode"
- (Semantic.GlobalReference intrinsicTarget)
- actualTarget
- assertEqual "intrinsic target object"
- intrinsicTarget invalidTarget
- other ->
- assertFailure
- (case other of
- Declaration.DriverSucceeded{} ->
- "ordinary binding accepted an intrinsic target"
- Declaration.DriverFailed failure _prefix ->
- "unexpected intrinsic-target failure: " <> show failure
- Declaration.DriverSealFailed failure _prefix ->
- "intrinsic target reached sealing: " <> show failure)
-
- conflictObject <- pure (opaqueFixtureObject conflictFixture)
- (_conflictBatch, conflicting) <-
- publishWith Semantic.GlobalReference conflictFixture conflictObject
- collision <- runFixtureDriver rootFixture
- [freshProducer, conflicting]
- (pure ())
- case collision of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- (Declaration.ImportedGlobalCollision
- actualKey firstTarget secondTarget))
- _prefix -> do
- assertEqual "colliding global key" key actualKey
- assertEqual "first imported target"
- (Semantic.GlobalReference target)
- firstTarget
- assertEqual "second imported target"
- (Semantic.GlobalReference
- (Identity.assertedObjectId conflictObject))
- secondTarget
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("unexpected imported collision: " <> show failure)
- Declaration.DriverSucceeded{} ->
- assertFailure "unequal imported bindings did not collide"
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure
- ("global collision reached sealing: " <> show failure)
-
- let theory = Identity.theoryId (fixtureFoundation producerFixture)
- transparentBody = Core.COpaqueInteger 0
- transparentTarget =
- Identity.transparentObjectId
- theory Core.TySet transparentBody
- transparentObject =
- Identity.assertedObject
- transparentTarget
- (Identity.TransparentObjectContent
- theory Core.TySet transparentBody)
- (_referenceBatch, referenceProducer) <-
- publishWith
- Semantic.GlobalReference
- producerFixture
- transparentObject
- (_expansionBatch, expansionProducer) <-
- publishWith
- Semantic.TransparentExpansion
- conflictFixture
- transparentObject
- modeCollision <- runFixtureDriver rootFixture
- [referenceProducer, expansionProducer]
- (pure ())
- case modeCollision of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- (Declaration.ImportedGlobalCollision
- actualKey firstTarget secondTarget))
- _prefix -> do
- assertEqual "mode collision key" key actualKey
- assertEqual "reference target"
- (Semantic.GlobalReference transparentTarget)
- firstTarget
- assertEqual "expansion target"
- (Semantic.TransparentExpansion transparentTarget)
- secondTarget
- other ->
- assertFailure
- (case other of
- Declaration.DriverSucceeded{} ->
- "different global target modes did not collide"
- Declaration.DriverFailed failure _prefix ->
- "unexpected mode-collision failure: " <> show failure
- Declaration.DriverSealFailed failure _prefix ->
- "mode collision reached sealing: " <> show failure)
-
-data FixtureSealed = FixtureSealed
- !Semantic.SemanticInterface
- !Declaration.ImportedModuleEvidence
-
-foldsTransitiveAndDiamondEvidence :: Assertion
-foldsTransitiveAndDiamondEvidence = do
- baseFixture <- makeNamedFixture "base"
- middleFixture <- makeNamedFixture "middle"
- transitiveFixture <- makeNamedFixture "transitive"
- leftFixture <- makeNamedFixture "left"
- rightFixture <- makeNamedFixture "right"
- diamondFixture <- makeNamedFixture "diamond"
- conflictLeftFixture <- makeNamedFixture "conflict-left"
- conflictRightFixture <- makeNamedFixture "conflict-right"
- conflictRootFixture <- makeNamedFixture "conflict-root"
-
- (base, baseFingerprint) <-
- sealFactFixture baseFixture [] "transitive-shared"
- middle <- snd <$> sealFixture middleFixture [base] (pure ())
- transitive <- sealUsingImportedFact
- transitiveFixture [middle] baseFingerprint
- assertLocalFactOrdinalZero "transitive importer" transitive
-
- left <- snd <$> sealFixture leftFixture [base] (pure ())
- right <- snd <$> sealFixture rightFixture [base] (pure ())
- diamond <- sealUsingImportedFact
- diamondFixture [left, right] baseFingerprint
- assertLocalFactOrdinalZero "diamond importer" diamond
-
- (conflictLeft, leftFingerprint) <-
- sealFactFixture conflictLeftFixture [] "diamond-conflict"
- (conflictRight, rightFingerprint) <-
- sealFactFixture conflictRightFixture [] "diamond-conflict"
- conflict <- runFixtureDriver
- conflictRootFixture
- [conflictLeft, conflictRight]
- (pure ())
- case conflict of
- Declaration.DriverFailed
- (Declaration.DriverDeclarationFailed
- (Declaration.ImportedAliasCollision
- alias
- (Declaration.ImportedAliasOrigin
- _leftSlot firstTarget)
- (Declaration.ImportedAliasOrigin
- _rightSlot secondTarget)))
- _prefix -> do
- assertEqual "conflicting alias"
- (Semantic.semanticName "diamond-conflict")
- alias
- assertEqual "first alias origin"
- leftFingerprint
- firstTarget
- assertEqual "second alias origin"
- rightFingerprint
- secondTarget
- _ ->
- assertFailure "conflicting diamond alias was not rejected"
- where
- sealUsingImportedFact fixture parents fingerprint = do
- (batch, _sealed) <- sealFixture fixture parents do
- (_value, committed) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "use-transitive-import") do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture "local-after-import")
- Declaration.authorizeOmittedCandidate candidate do
- void (Declaration.useAuthorizedFact fingerprint)
- Declaration.recordOmittedUse
- pure committed
- pure batch
-
- assertLocalFactOrdinalZero label batch =
- case Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch) of
- [occurrence] ->
- assertEqual label
- (localFactOrdinal 0)
- (Semantic.factSlotOrdinal
- (Semantic.semanticFactSlot occurrence))
- facts ->
- assertFailure
- (label <> ": unexpected fact count "
- <> show (length facts))
-
-sealFactFixture
- :: Fixture
- -> [FixtureSealed]
- -> Text
- -> IO
- ( FixtureSealed
- , Semantic.SemanticFactOccurrenceFingerprint
- )
-sealFactFixture fixture parents alias = do
- (batch, sealed) <- sealFixture fixture parents do
- (_value, committed) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId
- (TextEncoding.encodeUtf8 alias)) do
- candidate <- Declaration.reserveCandidate
- (factSpec fixture alias)
- Declaration.authorizeSourceAxiomCandidate candidate
- pure committed
- case Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch) of
- [occurrence] ->
- pure
- ( sealed
- , Semantic.semanticFactFingerprint occurrence
- )
- facts ->
- assertFailure
- ("unexpected sealed fact count: " <> show (length facts))
- >> fail "unreachable"
-
-sealFixture
- :: Fixture
- -> [FixtureSealed]
- -> Declaration.ModuleDriver Text value
- -> IO (value, FixtureSealed)
-sealFixture fixture parents action = do
- outcome <- runFixtureDriver fixture parents action
- case outcome of
- Declaration.DriverSucceeded value interface prefix _closure ->
- pure
- ( value
- , FixtureSealed
- interface
- (Declaration.freshImportedModuleEvidence
- [ evidence
- | FixtureSealed _interface evidence <- parents
- ]
- interface
- prefix)
- )
- Declaration.DriverFailed failure _prefix ->
- assertFailure ("fixture failed: " <> show failure)
- >> fail "unreachable"
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure ("fixture did not seal: " <> show failure)
- >> fail "unreachable"
-
-runFixtureDriver
- :: Fixture
- -> [FixtureSealed]
- -> Declaration.ModuleDriver Text value
- -> IO (Declaration.DriverResult Text value)
-runFixtureDriver fixture parents action = do
- result <- Declaration.runModuleDriver
- (fixtureFoundation fixture)
- (fixtureOwner fixture)
- [ Semantic.semanticInterfaceAssertedId interface
- | FixtureSealed interface _evidence <- parents
- ]
- unavailableVampireResolver
- Declaration.FreshValidation
- do
- traverse_
- (\(FixtureSealed _interface evidence) ->
- Declaration.importSealedModuleDriver evidence)
- parents
- action
- expectRight result
-
-requireSingleOccurrence
- :: Declaration.CommittedDeclarationBatch
- -> Declaration.ModuleDriver
- Declaration.DeclarationError
- Semantic.SemanticFactOccurrence
-requireSingleOccurrence batch =
- case Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch) of
- [occurrence] ->
- pure occurrence
- _ ->
- Declaration.failModuleDriver
- Declaration.ProofDeclarationMustProduceOneFact
-
-expectRight :: Show error => Either error value -> IO value
-expectRight = \case
- Left err ->
- assertFailure (show err) >> fail "unreachable"
- Right value ->
- pure value
-
-expectRightIO :: Show error => IO (Either error value) -> IO value
-expectRightIO action =
- action >>= expectRight
-
-withOpenedStore
- :: Fixture
- -> FilePath
- -> (Store.Store -> IO value)
- -> IO value
-withOpenedStore fixture root action =
- bracket
- (expectRightIO
- (Store.openStore
- (root Posix.</> "store.sqlite")
- (Identity.theoryId (fixtureFoundation fixture))))
- (Store.closeStore . snd)
- (action . snd)
-
-withTemporaryDirectory :: String -> (FilePath -> IO a) -> IO a
-withTemporaryDirectory template =
- bracket create Directory.removePathForcibly
- where
- create = do
- root <- Directory.getTemporaryDirectory
- (path, handle) <- openTempFile root template
- hClose handle
- Directory.removeFile path
- Directory.createDirectory path
- pure path
diff --git a/source/Test/Unit/Foundation.hs b/source/Test/Unit/Foundation.hs
deleted file mode 100644
index 17ff526..0000000
--- a/source/Test/Unit/Foundation.hs
+++ /dev/null
@@ -1,284 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module Test.Unit.Foundation (unitTests) where
-
-import Base
-import Checking.Core
-import Checking.Foundation
-
-import Data.List qualified as List
-import Data.Set qualified as Set
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "Foundation manifest"
- [ testCase
- "accepts the exact compiled foundation"
- acceptsCompiledFoundation
- , testCase
- "rejects incomplete and altered manifests"
- rejectsManifestMutations
- , testCase
- "classifies the exact UnivOf schemas"
- classifiesUnivOfSchemas
- , testCase
- "selects only intrinsic characteristic dependencies"
- selectsOnlyIntrinsicCharacteristicDependencies
- ]
-
-acceptsCompiledFoundation :: Assertion
-acceptsCompiledFoundation = do
- foundation <-
- either
- (assertFailure . show)
- pure
- checkedFoundation
- assertEqual
- "intrinsic coverage"
- [minBound .. maxBound]
- (fst <$> compiledFoundationIntrinsicRows)
- assertEqual
- "guarded-rule coverage"
- [minBound .. maxBound]
- [ tag
- | FoundationRuleInput tag _signature <-
- compiledFoundationRuleRows
- ]
- for_ [minBound .. maxBound] \tag ->
- assertEqual
- ("closed proposition type for " <> show tag)
- TyProp
- (frozenCoreType
- (foundationAxiomFrozen foundation tag))
-
-selectsOnlyIntrinsicCharacteristicDependencies :: Assertion
-selectsOnlyIntrinsicCharacteristicDependencies = do
- let separation =
- CApp
- (CApp (CIntrinsic Sep) (CBound 0))
- (CLam TySet CFalsum)
- underUniverse =
- CApp (CIntrinsic UnivOf) separation
- assertEqual
- "separation is found recursively without a universe bundle"
- (Set.singleton SeparationCharacteristic)
- (foundationAxiomDependencies underUniverse)
-
-rejectsManifestMutations :: Assertion
-rejectsManifestMutations = do
- let withoutMinimal =
- List.filter
- (\case
- FoundationAxiomInput
- UnivOfMinimal
- _syntax
- _backendClass ->
- False
- _ ->
- True)
- compiledFoundationAxiomRows
- wrongUnivType =
- [ if tag == UnivOf
- then (tag, TySet)
- else row
- | row@(tag, _coreType) <-
- compiledFoundationIntrinsicRows
- ]
- duplicatedEmpty =
- case findAxiomInput EmptyCharacteristic of
- Just row ->
- row : compiledFoundationAxiomRows
- Nothing ->
- impossible
- "compiled manifest omitted EmptyCharacteristic"
- alteredEmpty =
- replaceAxiomInput
- EmptyCharacteristic
- (FoundationAxiomInput
- EmptyCharacteristic
- (coreOpaqueInteger 0)
- FoundationFofProjectable)
- alteredExtensionality =
- replaceAxiomInput
- SetExtensionality
- (FoundationAxiomInput
- SetExtensionality
- coreFalsum
- FoundationFofProjectable)
- misclassifiedEmpty =
- case findAxiomInput EmptyCharacteristic of
- Just
- (FoundationAxiomInput
- tag
- syntax
- _backendClass) ->
- replaceAxiomInput
- tag
- (FoundationAxiomInput
- tag
- syntax
- (FoundationRequiresTh0
- (HigherOrderLambda :| [])))
- Nothing ->
- impossible
- "compiled manifest omitted EmptyCharacteristic"
- withoutLeast =
- [ row
- | row@(FoundationRuleInput tag _signature) <-
- compiledFoundationRuleRows
- , tag /= SetLfpLeast
- ]
- alteredInductSignature =
- [ if tag == SetLfpInduct
- then
- FoundationRuleInput
- tag
- (KernelRuleSignature [TySet] 0)
- else row
- | row@(FoundationRuleInput tag _signature) <-
- compiledFoundationRuleRows
- ]
- assertAuditContains
- (== MissingFoundationAxiom UnivOfMinimal)
- (auditFoundationManifest
- compiledFoundationIntrinsicRows
- compiledFoundationRuleRows
- withoutMinimal)
- assertAuditContains
- (== FoundationIntrinsicTypeMismatch
- UnivOf
- (TySet `TyArrow` TySet)
- TySet)
- (auditFoundationManifest
- wrongUnivType
- compiledFoundationRuleRows
- compiledFoundationAxiomRows)
- assertAuditContains
- (== MissingFoundationRule SetLfpLeast)
- (auditFoundationManifest
- compiledFoundationIntrinsicRows
- withoutLeast
- compiledFoundationAxiomRows)
- assertAuditContains
- (\case
- FoundationRuleSignatureMismatch
- SetLfpInduct
- _expected
- (KernelRuleSignature [TySet] 0) ->
- True
- _ ->
- False)
- (auditFoundationManifest
- compiledFoundationIntrinsicRows
- alteredInductSignature
- compiledFoundationAxiomRows)
- assertAuditContains
- (== DuplicateFoundationAxiom EmptyCharacteristic)
- (auditFoundationManifest
- compiledFoundationIntrinsicRows
- compiledFoundationRuleRows
- duplicatedEmpty)
- assertAuditContains
- (\case
- FoundationAxiomIllTyped
- EmptyCharacteristic
- (ExpectedCoreType TyProp TySet) ->
- True
- _ ->
- False)
- (auditFoundationManifest
- compiledFoundationIntrinsicRows
- compiledFoundationRuleRows
- alteredEmpty)
- assertAuditContains
- (== FoundationAxiomStatementMismatch
- SetExtensionality)
- (auditFoundationManifest
- compiledFoundationIntrinsicRows
- compiledFoundationRuleRows
- alteredExtensionality)
- assertAuditContains
- (== FoundationAxiomBackendClassMismatch
- EmptyCharacteristic
- (FoundationRequiresTh0
- (HigherOrderLambda :| []))
- FoundationFofProjectable)
- (auditFoundationManifest
- compiledFoundationIntrinsicRows
- compiledFoundationRuleRows
- misclassifiedEmpty)
-
-classifiesUnivOfSchemas :: Assertion
-classifiesUnivOfSchemas = do
- foundation <-
- either
- (assertFailure . show)
- pure
- checkedFoundation
- for_
- [ UnivOfContains
- , UnivOfTransitive
- , UnivOfFamilyUnionClosed
- , UnivOfPowerSetClosed
- ]
- \tag ->
- assertEqual
- (show tag)
- FoundationFofProjectable
- (foundationAxiomBackendClass foundation tag)
- for_
- [ UnivOfReplacementClosed
- , UnivOfMinimal
- ]
- \tag ->
- case foundationAxiomBackendClass foundation tag of
- FoundationRequiresTh0 exclusions ->
- assertBool
- (show tag <> " has a structural exclusion")
- (not (null exclusions))
- FoundationFofProjectable ->
- assertFailure
- (show tag <> " was classified as FOF")
-
-findAxiomInput
- :: FoundationAxiomTag
- -> Maybe FoundationAxiomInput
-findAxiomInput wanted =
- List.find
- (\case
- FoundationAxiomInput tag _syntax _backendClass ->
- tag == wanted)
- compiledFoundationAxiomRows
-
-replaceAxiomInput
- :: FoundationAxiomTag
- -> FoundationAxiomInput
- -> [FoundationAxiomInput]
-replaceAxiomInput wanted replacement =
- fmap
- (\row ->
- case row of
- FoundationAxiomInput tag _syntax _backendClass
- | tag == wanted ->
- replacement
- _ ->
- row)
- compiledFoundationAxiomRows
-
-assertAuditContains
- :: (FoundationManifestError -> Bool)
- -> Either
- (NonEmpty FoundationManifestError)
- FoundationManifestAudit
- -> Assertion
-assertAuditContains predicate = \case
- Left errors ->
- assertBool
- ("expected error not found in " <> show errors)
- (any predicate errors)
- Right _audit ->
- assertFailure
- "expected foundation-manifest audit to fail"
diff --git a/source/Test/Unit/Html.hs b/source/Test/Unit/Html.hs
deleted file mode 100644
index c7f24c4..0000000
--- a/source/Test/Unit/Html.hs
+++ /dev/null
@@ -1,225 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Unit.Html (unitTests) where
-
-import Base
-import Felix.Parse qualified as Parse
-import Felix.Source
-import Felix.Source.Graph
-import Felix.Workspace qualified as Workspace
-import Render.Html qualified as Html
-import Render.Html.Context
-import Render.Html.Layout
-import Report.Location (Location, pattern Nowhere)
-import Syntax.Abstract
-
-import Data.Text qualified as Text
-import Data.Text.IO qualified as TextIO
-import Data.List.NonEmpty qualified as NonEmpty
-import System.Directory qualified as Directory
-import Test.Tasty
-import Test.Tasty.HUnit
-
-unitTests :: TestTree
-unitTests = testGroup "HTML renderer"
- [ testCase "one shared index resolves local and cross-page previews" referencePreviews
- , testCase "missing reference preview data falls back to readable text" missingReferenceFallback
- , testCase "datatype rendering omits unchecked derived facts" datatypeDerivedFactsAreOmitted
- ]
-
-referencePreviews :: Assertion
-referencePreviews = do
- environment <- expectRight =<< Workspace.prepareDefaultWorkspaceEnvironment
- graph <-
- expectRight =<<
- Workspace.prepareDefaultSourceGraph
- "test/html-fixtures/root-preview.tex"
- workspace <-
- expectRight =<< Parse.parseResolvedSourceGraph graph
- hints <- TextIO.readFile "library/lexicon.tsv"
- layout <-
- expectRight
- (layoutHtmlSourceGraph
- (Workspace.workspaceHtmlMountPrefixes environment)
- graph)
- let nodes = Parse.parsedWorkspaceImportedBeforeImporter workspace
- sourceBlocks =
- (\node ->
- ( Parse.parsedModuleResolved node
- , Parse.parsedModuleBlocks node
- ))
- <$> nodes
- (renderIndex, pages) =
- Html.buildRenderIndex sourceBlocks
- rootPage = NonEmpty.last pages
- context <-
- expectRight
- (htmlRenderContext
- layout
- (Html.htmlPagePresentationSource rootPage))
- html <-
- expectRight
- (Html.renderDocument
- context
- hints
- renderIndex
- rootPage)
- let supportScript = Html.supportScriptAssetContents
- assertContains "local references keep page anchors" "href=\"#local_prop\"" html
- assertContains "local references point previews at the visible target block" "data-reference-label=\"local_prop\" data-preview-target-id=\"local_prop\"" html
- assertNotContains "local references do not use hidden preview ids" "data-reference-label=\"local_prop\" data-preview-id=\"" html
- assertContains "visible target blocks expose preview metadata" "id=\"local_prop\" data-preview-kind=\"Proposition\" data-preview-label=\"local_prop\"" html
- assertContains "imported references get preview metadata" "data-reference-label=\"imported_prop\"" html
- assertContains "imported references link to their relative encoded theory route" "href=\"imported-preview#imported_prop\"" html
- assertContains "imported references still use hidden preview templates" "data-reference-label=\"imported_prop\" data-preview-id=\"reference-preview-" html
- assertNotContains "imported references do not get broken page anchors" "href=\"#imported_prop\"" html
- assertNotContains "imported references are not non-clickable spans" "<span class=\"ref-badge has-preview\" data-reference-label=\"imported_prop\"" html
- assertCount "hidden preview store only contains the imported fixture preview" 1 "class=\"reference-preview-template\"" html
- assertContains "page grid is scoped to an explicit shell" "class=\"page-layout\"" html
- assertNotContains "page grid does not apply to every body div" "body > div" html
- assertContains "page heading uses the selected mounted source" "<h1>project:test/html-fixtures/root-preview.tex</h1>" html
- assertContains "imported preview records its mounted source" "project:test/html-fixtures/imported-preview.tex" html
- assertContains "imported preview source links to the same route" "href=\"imported-preview\"><code>project:test/html-fixtures/imported-preview.tex</code>" html
- assertContains "imported source renders on its own line" "class=\"reference-preview-source\"" html
- assertContains "multi-reference rendering preserves the comma separator" ", <a href=\"imported-preview#imported_prop\" class=\"ref-badge has-preview\" data-reference-label=\"imported_prop\"" html
- assertContains "calculation justifications also use target previews" "Step 2: by <a href=\"#local_prop\" class=\"ref-badge has-preview\" data-reference-label=\"local_prop\" data-preview-target-id=\"local_prop\"" html
- assertContains "large reference lists collapse to an ellipsis trigger" "Follows by <span class=\"ref-badge has-preview ref-badge-group\" data-preview-group=\"true\" data-reference-label=\"5 references\"" html
- assertContains "collapsed references keep current-page item metadata" "data-reference-label=\"group_source\" data-preview-link=\"#group_source\" data-preview-target-id=\"group_source\"" html
- assertContains "collapsed references keep imported item metadata" "data-reference-label=\"imported_prop\" data-preview-link=\"imported-preview#imported_prop\" data-preview-id=\"reference-preview-" html
- assertNotContains "collapsed references do not inline the long list" "Follows by <a href=\"#local_prop\" class=\"ref-badge has-preview\" data-reference-label=\"local_prop\" data-preview-target-id=\"local_prop\" aria-describedby=\"reference-preview-popup\">local_prop</a>, <a href=\"#uses_refs\"" html
- assertContains "collapsed tooltips compose full preview templates" "const preview = cloneHiddenPreview(item) || buildCurrentPreview(item) || buildMissingPreview(item);" supportScript
- assertContains "collapsed tooltip labels become links" "template.append(linkGroupHeading(item, preview));" supportScript
- assertContains "collapsed tooltip labels use generated reference links" "link.href = href;" supportScript
- assertContains "collapsed tooltip heading links have hover affordance" ".reference-preview-heading a:hover," html
- assertContains "collapsed tooltips use stacked preview sections" "className = 'reference-preview-group-template'" supportScript
- assertContains "visible preview popup accepts pointer interaction" "pointer-events: auto;" html
- assertContains "preview popup uses a wider bounded layout" "width: 44rem;" html
- assertContains "preview popup uses a taller bounded layout" "max-height: min(34rem, calc(100vh - 2rem));" html
- assertContains "behavior loads from the shared external script asset" "src=\"../../_static/naproche-html.js\"" html
- assertNotContains "inline script bundles are not emitted" "<script type=\"text/javascript\">" html
- assertContains "preview popup cancels delayed hide on pointer entry" "popup.addEventListener('pointerenter', clearHideTimer);" supportScript
- assertContains "preview popup schedules delayed hide on pointer exit" "popup.addEventListener('pointerleave', scheduleHide);" supportScript
- assertContains "group click pins the preview popup" "showPreview(trigger, event, true);" supportScript
- assertContains "group keyboard activation pins the preview popup" "showPreview(trigger, null, true);" supportScript
- assertContains "preview statements use a full-width paragraph" "class=\"reference-preview-statement\"" html
- assertContains "preview popup is emitted once" "id=\"reference-preview-popup\"" html
-
-missingReferenceFallback :: Assertion
-missingReferenceFallback = do
- let proof = Qed (Just Nowhere) (JustificationRef ("missing_ref" :| []))
- blocks = [BlockProof Nowhere proof Nowhere]
- html <- renderSynthetic blocks
- assertContains "missing references remain visible" "missing_ref" html
- assertNotContains "missing references do not claim preview content" "data-preview-id=" html
-
-datatypeDerivedFactsAreOmitted :: Assertion
-datatypeDerivedFactsAreOmitted = do
- let blocks =
- [ propformDatatypeBlock Nowhere
- , referenceClaimBlock "uses_datatype_fact"
- , referenceProofBlock "propform_induct"
- ]
- html <- renderSynthetic blocks
- assertContains "datatype declarations remain visible" "Datatype of " html
- assertContains "derived fact references remain readable" "propform_induct" html
- assertNotContains "unchecked datatype facts are not rendered" "<summary>Derived facts</summary>" html
- assertNotContains "unchecked datatype facts do not become preview targets" "data-preview-label=\"propform_induct\"" html
-
-renderSynthetic :: [Block] -> IO Text
-renderSynthetic blocks = do
- currentDirectory <- Directory.getCurrentDirectory
- mounts <-
- expectRight =<<
- prepareSourceMounts
- [(sourceMountId "project", currentDirectory)]
- request <-
- expectRight
- (searchedRoot "test/html-fixtures/root-preview.tex")
- graph <-
- expectRight =<<
- buildResolvedSourceGraph mounts request
- layout <-
- expectRight
- (layoutHtmlSourceGraph
- [(sourceMountId "project", [])]
- graph)
- context <-
- expectRight
- (htmlRenderContext
- layout
- (sourceGraphRootSource graph))
- let (renderIndex, page :| _remainingPages) =
- Html.buildRenderIndex
- ((sourceGraphRootSource graph, blocks) :| [])
- expectRight
- (Html.renderDocument
- context
- ""
- renderIndex
- page)
-
-expectRight :: (Show e, HasCallStack) => Either e a -> IO a
-expectRight = \case
- Left err ->
- assertFailure ("expected Right, got Left " <> show err)
- Right value ->
- pure value
-
-propformDatatypeBlock :: Location -> Block
-propformDatatypeBlock blockLoc =
- BlockData blockLoc Nothing "propform" propformDatatype
-
-propformDatatype :: Datatype
-propformDatatype =
- Datatype
- { datatypeHeadExpr = ExprOp Nowhere (constSymbol "propform") []
- , datatypeClauses =
- DatatypeClause (ExprOp Nowhere (constSymbol "propbot") []) (ExprOp Nowhere (constSymbol "propform") []) [] :|
- [ DatatypeClause (ExprOp Nowhere (unarySymbol "propvar") [ExprVar "n"]) (ExprOp Nowhere (constSymbol "propform") []) [("n", ExprOp Nowhere (constSymbol "naturals") [])]
- , DatatypeClause
- (ExprOp Nowhere (infixSymbol "propto") [ExprVar "p", ExprVar "q"])
- (ExprOp Nowhere (constSymbol "propform") [])
- [ ("p", ExprOp Nowhere (constSymbol "propform") [])
- , ("q", ExprOp Nowhere (constSymbol "propform") [])
- ]
- ]
- }
-
-referenceClaimBlock :: Marker -> Block
-referenceClaimBlock marker =
- BlockClaim Proposition Nowhere Nothing marker (Claim [] (StmtFormula (PropositionalConstant Nowhere IsTop)))
-
-referenceProofBlock :: Marker -> Block
-referenceProofBlock marker =
- BlockProof Nowhere (Qed (Just Nowhere) (JustificationRef (marker :| []))) Nowhere
-
-constSymbol :: Text -> FunctionSymbol
-constSymbol name =
- mkMixfixItem [Just (Command name)] (Marker name) NonAssoc
-
-unarySymbol :: Text -> FunctionSymbol
-unarySymbol name =
- mkMixfixItem [Just (Command name), Just InvisibleBraceL, Nothing, Just InvisibleBraceR] (Marker name) NonAssoc
-
-infixSymbol :: Text -> FunctionSymbol
-infixSymbol name =
- mkMixfixItem [Nothing, Just (Command name), Nothing] (Marker name) NonAssoc
-
-assertContains :: HasCallStack => String -> Text -> Text -> Assertion
-assertContains label needle haystack =
- assertBool
- (label <> "\nExpected to find: " <> Text.unpack needle)
- (needle `Text.isInfixOf` haystack)
-
-assertNotContains :: HasCallStack => String -> Text -> Text -> Assertion
-assertNotContains label needle haystack =
- assertBool
- (label <> "\nDid not expect to find: " <> Text.unpack needle)
- (not (needle `Text.isInfixOf` haystack))
-
-assertCount :: HasCallStack => String -> Int -> Text -> Text -> Assertion
-assertCount label expected needle haystack =
- assertEqual
- (label <> "\nExpected count for: " <> Text.unpack needle)
- expected
- (Text.count needle haystack)
diff --git a/source/Test/Unit/HtmlLayout.hs b/source/Test/Unit/HtmlLayout.hs
deleted file mode 100644
index a248f3b..0000000
--- a/source/Test/Unit/HtmlLayout.hs
+++ /dev/null
@@ -1,478 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Unit.HtmlLayout (unitTests) where
-
-import Base
-import Felix.Source
-import Felix.Source.Graph
-import Render.Html.Layout
-
-import Control.Exception (bracket)
-import Data.List qualified as List
-import Data.List.NonEmpty qualified as NonEmpty
-import Data.Text qualified as Text
-import System.Directory qualified as Directory
-import System.FilePath.Posix qualified as Posix
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "HTML layout"
- [ testCase
- "encodes URL segments canonically"
- encodesUrlSegments
- , testCase
- "renders relative typed URLs"
- rendersRelativeUrls
- , testCase
- "separates mounted route namespaces"
- separatesMountedNamespaces
- , testCase
- "routes searched and exact roots identically"
- routesRootFormsIdentically
- , testCase
- "requires an explicit mount for an external root"
- requiresExternalMount
- , testCase
- "reports URL and destination collisions independently"
- reportsRouteCollisions
- , testCase
- "rejects ancestor and descendant destinations"
- rejectsNestedDestinations
- , testCase
- "is independent of graph and configuration traversal order"
- isTraversalOrderIndependent
- ]
-
-
-encodesUrlSegments :: Assertion
-encodesUrlSegments = do
- let accepted =
- [ ("AZaz09-._~", "AZaz09-._~")
- , ("#?% \\", "%23%3F%25%20%5C")
- , ("über", "%C3%BCber")
- , ("%2f", "%252f")
- ]
- for_ accepted \(decoded, expected) ->
- assertEqual
- ("encoded segment " <> Text.unpack decoded)
- (Right expected)
- (renderUrlSegment <$> urlSegment decoded)
- let rejected =
- [ ("", EmptyUrlSegment)
- , (".", DotUrlSegment ".")
- , ("..", DotUrlSegment "..")
- , ("a/b", UrlSegmentContainsSeparator "a/b")
- ]
- for_ rejected \(decoded, expected) ->
- assertEqual
- ("rejected segment " <> Text.unpack decoded)
- (Left expected)
- (urlSegment decoded)
- assertEqual
- "fragment encoding"
- "#name%23%C3%BC"
- (renderUrlFragment "name#ü")
-
-rendersRelativeUrls :: Assertion
-rendersRelativeUrls = do
- let cases =
- [ ( ["library", "nested", "über"]
- , ["_static", "naproche-html.js"]
- , "../../_static/naproche-html.js"
- )
- , ( ["first", "entry"]
- , ["second", "entry"]
- , "../second/entry"
- )
- , ( ["mount", "entry"]
- , ["mount", "a?b"]
- , "a%3Fb"
- )
- ]
- for_ cases \(currentSegments, targetSegments, expected) -> do
- current <- expectRight (urlPath currentSegments)
- target <- expectRight (urlPath targetSegments)
- assertEqual
- "relative URL"
- expected
- (renderRelativeUrlPath current target)
- current <- expectRight (urlPath ["mount", "entry"])
- target <- expectRight (urlPath ["mount", "ü"])
- assertEqual
- "encoded path and fragment remain separate"
- "%C3%BC#part%23%3F"
- ( renderRelativeUrlPath current target
- <> renderUrlFragment "part#?"
- )
-
-separatesMountedNamespaces :: Assertion
-separatesMountedNamespaces =
- withTemporaryDirectory "felix-html-layout-mounts" \temp -> do
- let mountSpecifications =
- [ ("project", [])
- , ("library", ["library"])
- , ("debug", ["debug"])
- , ("external", ["external"])
- ]
- roots <- for mountSpecifications \(ident, _prefix) -> do
- let root = temp Posix.</> Text.unpack ident
- Directory.createDirectory root
- writeTheory (root Posix.</> "entry.tex") []
- pure (sourceMountId ident, root)
- mounts <- expectRight =<< prepareSourceMounts roots
- routes <- for mountSpecifications \(ident, prefix) -> do
- let sourcePath =
- temp
- Posix.</> Text.unpack ident
- Posix.</> "entry.tex"
- request <- expectRight =<< existingRoot sourcePath
- graph <- expectRight =<< buildResolvedSourceGraph mounts request
- layout <-
- expectRight
- (layoutHtmlSourceGraph
- [ (sourceMountId configuredId, configuredPrefix)
- | (configuredId, configuredPrefix) <-
- mountSpecifications
- ]
- graph)
- route <- requireRootRoute graph layout
- pure
- ( ident
- , renderUrlPath (routeUrlPath route)
- , safeRelativePathFilePath
- (routeDestination route)
- , prefix
- )
- assertEqual
- "mount URLs"
- [ ("project", "/entry")
- , ("library", "/library/entry")
- , ("debug", "/debug/entry")
- , ("external", "/external/entry")
- ]
- [ (ident, url) | (ident, url, _destination, _prefix) <- routes ]
- assertEqual
- "mount destinations"
- [ ("project", "entry.html")
- , ("library", "library/entry.html")
- , ("debug", "debug/entry.html")
- , ("external", "external/entry.html")
- ]
- [ (ident, destination)
- | (ident, _url, destination, _prefix) <- routes
- ]
-
-routesRootFormsIdentically :: Assertion
-routesRootFormsIdentically =
- withTemporaryDirectory "felix-html-layout-root-forms" \temp -> do
- let libraryRoot = temp Posix.</> "library"
- entry = libraryRoot Posix.</> "entry.tex"
- Directory.createDirectory libraryRoot
- writeTheory entry []
- mounts <- expectRight =<< prepareSourceMounts
- [ (sourceMountId "project", temp)
- , (sourceMountId "library", libraryRoot)
- ]
- searched <- expectRight (searchedRoot "library/entry.tex")
- exact <- expectRight =<< existingRoot entry
- searchedGraph <-
- expectRight =<< buildResolvedSourceGraph mounts searched
- exactGraph <-
- expectRight =<< buildResolvedSourceGraph mounts exact
- let configuration =
- [ (sourceMountId "project", [])
- , (sourceMountId "library", ["library"])
- ]
- searchedLayout <-
- expectRight
- (layoutHtmlSourceGraph configuration searchedGraph)
- exactLayout <-
- expectRight
- (layoutHtmlSourceGraph configuration exactGraph)
- searchedRoute <-
- requireRootRoute searchedGraph searchedLayout
- exactRoute <-
- requireRootRoute exactGraph exactLayout
- assertEqual "selected route" searchedRoute exactRoute
- assertEqual
- "most-specific URL"
- "/library/entry"
- (renderUrlPath (routeUrlPath searchedRoute))
-
-requiresExternalMount :: Assertion
-requiresExternalMount =
- withTemporaryDirectory "felix-html-layout-external" \temp -> do
- let projectRoot = temp Posix.</> "project"
- externalRoot = temp Posix.</> "vendor"
- externalEntry = externalRoot Posix.</> "entry.tex"
- Directory.createDirectory projectRoot
- Directory.createDirectory externalRoot
- writeTheory externalEntry []
- request <- expectRight =<< existingRoot externalEntry
- projectMounts <- expectRight =<< prepareSourceMounts
- [(sourceMountId "project", projectRoot)]
- outsideResult <-
- buildResolvedSourceGraph projectMounts request
- case outsideResult of
- Left RootOutsideConfiguredMount{} ->
- pure ()
- result ->
- assertFailure
- ("expected external root rejection, got "
- <> show result)
- mounted <- expectRight =<< prepareSourceMounts
- [ (sourceMountId "project", projectRoot)
- , (sourceMountId "external", externalRoot)
- ]
- graph <- expectRight =<< buildResolvedSourceGraph mounted request
- layout <-
- expectRight
- (layoutHtmlSourceGraph
- [ (sourceMountId "project", [])
- , (sourceMountId "external", ["vendor"])
- ]
- graph)
- route <- requireRootRoute graph layout
- assertEqual
- "external URL"
- "/vendor/entry"
- (renderUrlPath (routeUrlPath route))
-
-reportsRouteCollisions :: Assertion
-reportsRouteCollisions = do
- reportsPageCollisions
- reportsAssetUrlCollision
-
-reportsPageCollisions :: Assertion
-reportsPageCollisions =
- withTemporaryDirectory "felix-html-layout-page-collision" \temp -> do
- let firstRoot = temp Posix.</> "first"
- secondRoot = temp Posix.</> "second"
- firstEntry = firstRoot Posix.</> "two" Posix.</> "a.tex"
- Directory.createDirectory firstRoot
- Directory.createDirectory secondRoot
- Directory.createDirectory (firstRoot Posix.</> "two")
- writeTheory (secondRoot Posix.</> "a.tex") []
- writeTheory firstEntry ["a.tex"]
- mounts <- expectRight =<< prepareSourceMounts
- [ (sourceMountId "first", firstRoot)
- , (sourceMountId "second", secondRoot)
- ]
- request <- expectRight =<< existingRoot firstEntry
- graph <- expectRight =<< buildResolvedSourceGraph mounts request
- let configuration =
- [ (sourceMountId "first", ["one"])
- , (sourceMountId "second", ["one", "two"])
- ]
- case layoutHtmlSourceGraph configuration graph of
- Left
- (CollidingHtmlRoutes
- [HtmlUrlRouteCollision url owners]
- [HtmlDestinationRouteCollision destination
- destinationOwners]) -> do
- assertEqual
- "canonical URL collision"
- "/one/two/a"
- (renderUrlPath url)
- assertEqual
- "URL owners"
- (NonEmpty.toList owners)
- (NonEmpty.toList destinationOwners)
- assertEqual
- "destination collision"
- "one/two/a.html"
- (safeRelativePathFilePath destination)
- result ->
- assertFailure
- ("expected paired route collisions, got "
- <> show result)
-
-reportsAssetUrlCollision :: Assertion
-reportsAssetUrlCollision =
- withTemporaryDirectory "felix-html-layout-asset-collision" \temp -> do
- let entry =
- temp
- Posix.</> "_static"
- Posix.</> "naproche-html.js.tex"
- Directory.createDirectory (temp Posix.</> "_static")
- writeTheory entry []
- mounts <- expectRight =<< prepareSourceMounts
- [(sourceMountId "project", temp)]
- request <-
- expectRight
- (searchedRoot "_static/naproche-html.js.tex")
- graph <- expectRight =<< buildResolvedSourceGraph mounts request
- case
- layoutHtmlSourceGraph
- [(sourceMountId "project", [])]
- graph of
- Left
- (CollidingHtmlRoutes
- [HtmlUrlRouteCollision url _owners]
- []) ->
- assertEqual
- "page/asset URL collision"
- "/_static/naproche-html.js"
- (renderUrlPath url)
- result ->
- assertFailure
- ("expected URL-only asset collision, got "
- <> show result)
-
-rejectsNestedDestinations :: Assertion
-rejectsNestedDestinations =
- withTemporaryDirectory "felix-html-layout-nested" \temp -> do
- let nestedDirectory = temp Posix.</> "a.html"
- Directory.createDirectory nestedDirectory
- writeTheory (temp Posix.</> "a.tex") []
- writeTheory (nestedDirectory Posix.</> "b.tex") []
- writeTheory
- (temp Posix.</> "entry.tex")
- ["a.tex", "a.html/b.tex"]
- mounts <- expectRight =<< prepareSourceMounts
- [(sourceMountId "project", temp)]
- request <- expectRight (searchedRoot "entry.tex")
- graph <- expectRight =<< buildResolvedSourceGraph mounts request
- case layoutHtmlSourceGraph
- [(sourceMountId "project", [])]
- graph of
- Left
- (CollidingHtmlRoutes
- []
- [NestedHtmlDestinationRouteCollision
- ancestor
- ancestorOwner
- descendant
- descendantOwner]) -> do
- assertEqual
- "ancestor destination"
- "a.html"
- (safeRelativePathFilePath ancestor)
- assertEqual
- "ancestor owner"
- "a.tex"
- (pageOwnerPath ancestorOwner)
- assertEqual
- "descendant destination"
- "a.html/b.html"
- (safeRelativePathFilePath descendant)
- assertEqual
- "descendant owner"
- "a.html/b.tex"
- (pageOwnerPath descendantOwner)
- result ->
- assertFailure
- ("expected nested destination collision, got "
- <> show result)
- where
- pageOwnerPath = \case
- HtmlPage source ->
- safeRelativePathFilePath
- (resolvedSourceRelativePath source)
- HtmlSupportScript ->
- "<support script>"
-
-isTraversalOrderIndependent :: Assertion
-isTraversalOrderIndependent =
- withTemporaryDirectory "felix-html-layout-order" \temp -> do
- writeTheory (temp Posix.</> "a.tex") []
- writeTheory (temp Posix.</> "b.tex") []
- let root = temp Posix.</> "entry.tex"
- writeTheory root ["a.tex", "b.tex"]
- mounts <- expectRight =<< prepareSourceMounts
- [(sourceMountId "project", temp)]
- request <- expectRight (searchedRoot "entry.tex")
- firstGraph <-
- expectRight =<< buildResolvedSourceGraph mounts request
- writeTheory root ["b.tex", "a.tex"]
- secondGraph <-
- expectRight =<< buildResolvedSourceGraph mounts request
- let firstConfiguration =
- [ (sourceMountId "unused", ["unused"])
- , (sourceMountId "project", [])
- ]
- firstLayout <-
- expectRight
- (layoutHtmlSourceGraph
- firstConfiguration
- firstGraph)
- for_
- (zip
- (cycle [firstGraph, secondGraph])
- (List.permutations firstConfiguration))
- \(orderedGraph, configuration) -> do
- layout <-
- expectRight
- (layoutHtmlSourceGraph
- configuration
- orderedGraph)
- assertEqual
- "route table"
- firstLayout
- layout
-
- let collidingConfiguration =
- [ (sourceMountId "z", ["same"])
- , (sourceMountId "a", ["same"])
- , (sourceMountId "project", [])
- ]
- expectedCollision =
- layoutHtmlSourceGraph
- collidingConfiguration
- firstGraph
- for_
- (zip
- (cycle [firstGraph, secondGraph])
- (List.permutations collidingConfiguration))
- \(orderedGraph, configuration) ->
- assertEqual
- "collision diagnostic"
- expectedCollision
- (layoutHtmlSourceGraph
- configuration
- orderedGraph)
-
-
-requireRootRoute
- :: ResolvedSourceGraph
- -> HtmlLayout
- -> IO HtmlRoute
-requireRootRoute graph layout =
- case htmlPageRoute layout (sourceGraphRootSource graph) of
- Just route ->
- pure route
- Nothing -> do
- assertFailure "layout omitted the root source"
- pure (impossible "requireRootRoute: assertFailure returned")
-
-writeTheory :: FilePath -> [FilePath] -> IO ()
-writeTheory path imports =
- writeFile path
- (unlines
- (["\\import{" <> imported <> "}" | imported <- imports]
- <> [ "\\begin{axiom}\\label{route_fixture}"
- , " $x = x$."
- , "\\end{axiom}"
- ]))
-
-expectRight :: (Show e, HasCallStack) => Either e a -> IO a
-expectRight = \case
- Left err ->
- assertFailure ("expected Right, got Left " <> show err)
- Right value ->
- pure value
-
-withTemporaryDirectory :: String -> (FilePath -> IO a) -> IO a
-withTemporaryDirectory template =
- bracket create Directory.removePathForcibly
- where
- create = do
- systemTemp <- Directory.getTemporaryDirectory
- (path, handle) <- openTempFile systemTemp template
- hClose handle
- Directory.removeFile path
- Directory.createDirectory path
- pure path
diff --git a/source/Test/Unit/HtmlOutput.hs b/source/Test/Unit/HtmlOutput.hs
deleted file mode 100644
index 0087f82..0000000
--- a/source/Test/Unit/HtmlOutput.hs
+++ /dev/null
@@ -1,560 +0,0 @@
-{-# LANGUAGE NamedFieldPuns #-}
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Unit.HtmlOutput (unitTests) where
-
-import Base
-import Felix.Parse qualified as Parse
-import Felix.Source
-import Felix.Source.Graph qualified as SourceGraph
-import Render.Html qualified as Html
-import Render.Html.Export
-import Render.Html.Output
-
-import Control.Exception (bracket)
-import Data.ByteString qualified as ByteString
-import Data.List qualified as List
-import Data.Text qualified as Text
-import Data.Text.Encoding qualified as TextEncoding
-import System.Directory qualified as Directory
-import System.FilePath.Posix ((</>))
-import System.Posix.Files qualified as PosixFiles
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "HTML output"
- [ testCase
- "publishes a mounted multi-page UTF-8 export"
- publishesMountedExport
- , testCase
- "writes prepared strict bytes"
- writesPreparedBytes
- , testCase
- "attaches bytes only to reserved routes"
- attachesBytesToReservedRoutes
- , testCase
- "rejects a final symlink before publication"
- rejectsFinalSymlink
- , testCase
- "replaces hard-linked targets without changing peers"
- replacesHardLinkedTarget
- , testCase
- "rejects a FIFO before publication"
- rejectsFifo
- , testCase
- "reports and cleans the source-order publication prefix"
- reportsIncompletePublication
- ]
-
-
-publishesMountedExport :: Assertion
-publishesMountedExport =
- withTemporaryDirectory "felix-html-export" \temp -> do
- let projectRoot = temp </> "project"
- libraryRoot = temp </> "library"
- projectDirectory = projectRoot </> "docs"
- libraryDirectory = libraryRoot </> "shared"
- rootSource = projectDirectory </> "über #.tex"
- importedSource =
- libraryDirectory </> "sets #.tex"
- outputRoot = temp </> "html"
- rootPage = outputRoot </> "docs" </> "über #.html"
- importedPage =
- outputRoot
- </> "library"
- </> "shared"
- </> "sets #.html"
- supportAsset =
- outputRoot
- </> "_static"
- </> "naproche-html.js"
- configuration =
- [ (sourceMountId "project", [])
- , (sourceMountId "library", ["library"])
- ]
- hints =
- "relation\teq\t0\t<mo>=</mo>\n"
- Directory.createDirectory projectRoot
- Directory.createDirectory libraryRoot
- Directory.createDirectory projectDirectory
- Directory.createDirectory libraryDirectory
- writeImportedTheory importedSource
- writeRootTheory rootSource
- mounts <-
- expectRight =<<
- prepareSourceMounts
- [ (sourceMountId "project", projectRoot)
- , (sourceMountId "library", libraryRoot)
- ]
- searched <-
- expectRight
- (searchedRoot "docs/über #.tex")
- exact <-
- expectRight =<< existingRoot rootSource
- searchedExport <-
- expectRight =<<
- prepareTestHtmlExport
- configuration
- mounts
- searched
- hints
- exactExport <-
- expectRight =<<
- prepareTestHtmlExport
- configuration
- mounts
- exact
- hints
- assertEqual
- "root-form-independent destinations"
- (preparedHtmlArtifactDestination <$> searchedExport)
- (preparedHtmlArtifactDestination <$> exactExport)
-
- let artifacts = searchedExport
- rejectsArtifactEscape temp artifacts
-
- plan <-
- requirePlan =<<
- planHtmlOutput outputRoot artifacts
- outputExistsBeforePublication <-
- Directory.doesPathExist outputRoot
- assertBool
- "preflight created the output root"
- (not outputExistsBeforePublication)
- requirePublication =<< writeHtmlOutput plan
-
- rootText <- readUtf8 rootPage
- importedText <- readUtf8 importedPage
- supportText <- readUtf8 supportAsset
- assertContains
- "root heading"
- "<h1>project:docs/über #.tex</h1>"
- rootText
- assertContains
- "imported heading"
- "<h1>library:shared/sets #.tex</h1>"
- importedText
- assertContains
- "encoded imported reference"
- "href=\"../library/shared/sets%20%23#imported_prop\""
- rootText
- assertContains
- "encoded imported source link"
- "href=\"../library/shared/sets%20%23\"><code>library:shared/sets #.tex</code>"
- rootText
- assertContains
- "root support route"
- "src=\"../_static/naproche-html.js\""
- rootText
- assertContains
- "imported support route"
- "src=\"../../_static/naproche-html.js\""
- importedText
- for_ [rootText, importedText] \document ->
- assertContains
- "UTF-8 declaration"
- "<meta charset=\"utf-8\">"
- document
- assertEqual
- "support asset"
- Html.supportScriptAssetContents
- supportText
-
-rejectsArtifactEscape
- :: FilePath
- -> [PreparedHtmlArtifact]
- -> Assertion
-rejectsArtifactEscape temp artifacts = do
- let outputRoot = temp </> "escape-html"
- outsideRoot = temp </> "outside"
- outsideMarker = outsideRoot </> "unchanged"
- Directory.createDirectory outputRoot
- Directory.createDirectory outsideRoot
- ByteString.writeFile outsideMarker "outside"
- Directory.createDirectoryLink
- outsideRoot
- (outputRoot </> "docs")
- result <- planHtmlOutput outputRoot artifacts
- case result of
- Left
- (HtmlOutputParentEscapesRoot
- _parent
- canonicalParent) -> do
- expectedOutside <-
- Directory.canonicalizePath outsideRoot
- assertEqual
- "escaping route target"
- expectedOutside
- canonicalParent
- other ->
- assertFailure
- ("expected output-root escape rejection, got "
- <> showPlanResult other)
- outsideBytes <- ByteString.readFile outsideMarker
- assertEqual
- "escape planning changed the outside tree"
- "outside"
- outsideBytes
- supportExists <-
- Directory.doesPathExist
- (outputRoot </> "_static")
- assertBool
- "escape preflight created another destination"
- (not supportExists)
-
-writesPreparedBytes :: Assertion
-writesPreparedBytes =
- withTemporaryDirectory "felix-html-output-bytes" \temp -> do
- let outputRoot = temp </> "html"
- pageText = "∀ café"
- supportText = "const π = 3;"
- expectedPageBytes =
- ByteString.pack
- [ 0xe2, 0x88, 0x80
- , 0x20
- , 0x63, 0x61, 0x66
- , 0xc3, 0xa9
- ]
- artifacts <-
- makeArtifacts
- [ ( "nested/über.html"
- , TextEncoding.encodeUtf8 pageText
- )
- , ( "_static/naproche-html.js"
- , TextEncoding.encodeUtf8 supportText
- )
- ]
- publishArtifacts outputRoot artifacts
- pageBytes <-
- ByteString.readFile
- (outputRoot </> "nested" </> "über.html")
- supportBytes <-
- ByteString.readFile
- (outputRoot
- </> "_static"
- </> "naproche-html.js")
- assertEqual
- "exact page UTF-8 bytes"
- expectedPageBytes
- pageBytes
- assertEqual
- "exact support bytes"
- (TextEncoding.encodeUtf8 supportText)
- supportBytes
-
-attachesBytesToReservedRoutes :: Assertion
-attachesBytesToReservedRoutes =
- withTemporaryDirectory "felix-html-output-routes" \temp -> do
- let outputRoot = temp </> "html"
- reserved <- expectRight
- (traverse safeRelativePath
- ["page.html", "_static/naproche-html.js"])
- routes <- requireRoutePlan =<<
- planHtmlRoutes outputRoot reserved
- matching <- makeArtifacts
- [ ("page.html", "page")
- , ("_static/naproche-html.js", "support")
- ]
- case planHtmlOutputAgainst routes matching of
- Right _ ->
- pure ()
- Left failure ->
- assertFailure (show failure)
- mismatched <- makeArtifacts
- [ ("other.html", "other")
- , ("_static/naproche-html.js", "support")
- ]
- case planHtmlOutputAgainst routes mismatched of
- Left HtmlOutputRouteMismatch{} ->
- pure ()
- Left failure ->
- assertFailure
- ("unexpected route mismatch: " <> show failure)
- Right _ ->
- assertFailure "unreserved HTML route was accepted"
-
-rejectsFinalSymlink :: Assertion
-rejectsFinalSymlink =
- withTemporaryDirectory "felix-html-output-final-link" \temp -> do
- let outputRoot = temp </> "html"
- supportDirectory = outputRoot </> "_static"
- page = outputRoot </> "page.html"
- support =
- supportDirectory </> "naproche-html.js"
- outsideAsset = temp </> "outside.js"
- Directory.createDirectory outputRoot
- Directory.createDirectory supportDirectory
- ByteString.writeFile page "old page"
- ByteString.writeFile outsideAsset "outside asset"
- Directory.createFileLink outsideAsset support
- artifacts <-
- makeArtifacts
- [ ("page.html", "new page")
- , ("_static/naproche-html.js", "new support")
- ]
- result <- planHtmlOutput outputRoot artifacts
- case result of
- Left (HtmlOutputTargetIsSymbolicLink target) ->
- assertEqual "rejected target" support target
- other ->
- assertFailure
- ("expected final symlink rejection, got "
- <> showPlanResult other)
- pageBytes <- ByteString.readFile page
- outsideBytes <- ByteString.readFile outsideAsset
- supportIsLink <-
- Directory.pathIsSymbolicLink support
- assertEqual
- "page changed before complete preflight"
- "old page"
- pageBytes
- assertEqual
- "symlink referent changed"
- "outside asset"
- outsideBytes
- assertBool "final symlink was replaced" supportIsLink
-
-replacesHardLinkedTarget :: Assertion
-replacesHardLinkedTarget =
- withTemporaryDirectory "felix-html-output-hard-link" \temp -> do
- let outputRoot = temp </> "html"
- page = outputRoot </> "page.html"
- outsidePage = temp </> "outside.html"
- Directory.createDirectory outputRoot
- ByteString.writeFile outsidePage "outside page"
- PosixFiles.createLink outsidePage page
- artifacts <-
- makeArtifacts [("page.html", "new page")]
- publishArtifacts outputRoot artifacts
- outsideBytes <- ByteString.readFile outsidePage
- pageBytes <- ByteString.readFile page
- assertEqual
- "outside hard-link peer changed"
- "outside page"
- outsideBytes
- assertEqual "page was not replaced" "new page" pageBytes
-
-rejectsFifo :: Assertion
-rejectsFifo =
- withTemporaryDirectory "felix-html-output-fifo" \temp -> do
- let outputRoot = temp </> "html"
- page = outputRoot </> "page.html"
- Directory.createDirectory outputRoot
- PosixFiles.createNamedPipe page PosixFiles.ownerModes
- artifacts <-
- makeArtifacts [("page.html", "page")]
- result <- planHtmlOutput outputRoot artifacts
- case result of
- Left (HtmlOutputTargetNotRegularFile target) ->
- assertEqual "rejected target" page target
- other ->
- assertFailure
- ("expected FIFO rejection, got "
- <> showPlanResult other)
- pageStatus <-
- PosixFiles.getSymbolicLinkStatus page
- assertBool
- "FIFO target was replaced"
- (PosixFiles.isNamedPipe pageStatus)
-
-reportsIncompletePublication :: Assertion
-reportsIncompletePublication =
- withTemporaryDirectory "felix-html-output-incomplete" \temp -> do
- let outputRoot = temp </> "html"
- first = outputRoot </> "z.html"
- blocked = outputRoot </> "b.html"
- unpublished = outputRoot </> "a.html"
- artifacts <-
- makeArtifacts
- [ ("z.html", "first")
- , ("b.html", "blocked")
- , ("a.html", "unpublished")
- ]
- plan <-
- requirePlan =<<
- planHtmlOutput outputRoot artifacts
- Directory.createDirectory outputRoot
- Directory.createDirectory blocked
- result <- writeHtmlOutput plan
- case result of
- Left
- IncompleteHtmlPublication
- { committedHtmlDestinations
- , failedHtmlDestination
- } -> do
- expectedFirst <-
- expectRight
- (safeRelativePath "z.html")
- expectedBlocked <-
- expectRight
- (safeRelativePath "b.html")
- assertEqual
- "committed destinations"
- [expectedFirst]
- committedHtmlDestinations
- assertEqual
- "failed destination"
- expectedBlocked
- failedHtmlDestination
- Right () ->
- assertFailure
- "expected incomplete publication"
- firstBytes <- ByteString.readFile first
- unpublishedExists <-
- Directory.doesPathExist unpublished
- blockedIsDirectory <-
- Directory.doesDirectoryExist blocked
- outputEntries <-
- Directory.listDirectory outputRoot
- assertEqual "first artifact" "first" firstBytes
- assertBool
- "later artifact was published"
- (not unpublishedExists)
- assertBool
- "injected blocker was replaced"
- blockedIsDirectory
- assertBool
- "unpublished temporary files remain"
- (not
- (any
- (List.isInfixOf ".tmp")
- outputEntries))
-
-
-publishArtifacts
- :: FilePath
- -> [PreparedHtmlArtifact]
- -> IO ()
-publishArtifacts outputRoot artifacts = do
- plan <-
- requirePlan =<< planHtmlOutput outputRoot artifacts
- requirePublication =<< writeHtmlOutput plan
-
-makeArtifacts
- :: [(FilePath, ByteString.ByteString)]
- -> IO [PreparedHtmlArtifact]
-makeArtifacts artifacts =
- for artifacts \(path, bytes) -> do
- relative <- expectRight (safeRelativePath path)
- pure (preparedHtmlArtifact relative (Right bytes))
-
-requirePlan
- :: Either HtmlOutputError HtmlOutputPlan
- -> IO HtmlOutputPlan
-requirePlan =
- expectRight
-
-requireRoutePlan
- :: Either HtmlOutputError HtmlRoutePlan
- -> IO HtmlRoutePlan
-requireRoutePlan =
- expectRight
-
-requirePublication
- :: Either HtmlPublicationError ()
- -> IO ()
-requirePublication =
- expectRight
-
-showPlanResult
- :: Either HtmlOutputError HtmlOutputPlan
- -> String
-showPlanResult = \case
- Left err ->
- show err
- Right _plan ->
- "successful output plan"
-
-readUtf8 :: FilePath -> IO Text
-readUtf8 path = do
- bytes <- ByteString.readFile path
- case TextEncoding.decodeUtf8' bytes of
- Left err ->
- assertFailure
- ("invalid UTF-8 output: " <> show err)
- Right text ->
- pure text
-
-prepareTestHtmlExport
- :: [(SourceMountId, [Text])]
- -> SourceMounts
- -> RootRequest
- -> Text
- -> IO (Either HtmlExportError [PreparedHtmlArtifact])
-prepareTestHtmlExport configuration mounts request hints = do
- graph <-
- expectRight =<<
- SourceGraph.buildResolvedSourceGraph mounts request
- workspace <-
- expectRight =<< Parse.parseResolvedSourceGraph graph
- pure
- (prepareHtmlExport
- configuration
- (htmlPresentationFromParsedWorkspace workspace)
- hints)
-
-writeImportedTheory :: FilePath -> IO ()
-writeImportedTheory path =
- writeFile path
- (unlines
- [ "\\begin{proposition}\\label{imported_prop}"
- , " $i = i$."
- , "\\end{proposition}"
- ])
-
-writeRootTheory :: FilePath -> IO ()
-writeRootTheory path =
- writeFile path
- (unlines
- [ "\\import{shared/sets #.tex}"
- , "\\begin{proposition}\\label{local_prop}"
- , " $a = a$."
- , "\\end{proposition}"
- , "\\begin{proposition}\\label{uses_import}"
- , " $b = b$."
- , "\\end{proposition}"
- , "\\begin{proof}"
- , " Follows by \\cref{imported_prop}."
- , "\\end{proof}"
- ])
-
-assertContains
- :: String
- -> Text
- -> Text
- -> Assertion
-assertContains description needle haystack =
- assertBool
- (description <> ": missing " <> show needle)
- (needle `Text.isInfixOf` haystack)
-
-expectRight
- :: (Show e, HasCallStack)
- => Either e a
- -> IO a
-expectRight = \case
- Left err ->
- assertFailure
- ("expected Right, got Left " <> show err)
- Right value ->
- pure value
-
-withTemporaryDirectory
- :: String
- -> (FilePath -> IO a)
- -> IO a
-withTemporaryDirectory template =
- bracket create Directory.removePathForcibly
- where
- create = do
- systemTemp <-
- Directory.getTemporaryDirectory
- (path, handle) <-
- openTempFile systemTemp template
- hClose handle
- Directory.removeFile path
- Directory.createDirectory path
- pure path
diff --git a/source/Test/Unit/Identity.hs b/source/Test/Unit/Identity.hs
deleted file mode 100644
index 0cb46a5..0000000
--- a/source/Test/Unit/Identity.hs
+++ /dev/null
@@ -1,802 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module Test.Unit.Identity (unitTests) where
-
-import Base
-import Checking.Authority qualified as Authority
-import Checking.Core qualified as Core
-import Checking.Foundation qualified as Foundation
-import Checking.Identity qualified as Identity
-import Felix.Cache.Codec
-import Felix.Math.Codec
-import Felix.Module
-import Felix.Source
-
-import Control.Exception (bracket)
-import Data.ByteString qualified as ByteString
-import Data.Either (isLeft)
-import Data.List.NonEmpty qualified as NonEmpty
-import Data.Map.Strict qualified as Map
-import Data.Set qualified as Set
-import Data.Text qualified as Text
-import Numeric.Natural (Natural)
-import System.Directory qualified as Directory
-import System.FilePath.Posix qualified as Posix
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "Content identities"
- [ testCase "uses the frozen mathematical hash framing"
- hashesCanonicalFields
- , testCase "orders exhaustive foundation rows by stable tags"
- ordersFoundationManifestTags
- , testCase "uses the frozen source path codecs"
- encodesSourcePaths
- , testCase "separates durable namespaces from mount labels"
- separatesModuleOwnership
- , testCase "rejects duplicate canonical collection encodings"
- rejectsDuplicateCanonicalCollections
- , testCase "matches every frozen mathematical identity vector"
- matchesMathematicalIdentityVectors
- , testCase "validates recursive transparent object content"
- validatesTransparentObjectClosure
- , testCase "rejects cyclic and mismatched object content"
- rejectsInvalidObjectContent
- , testCase "validates proposition content and theorem closure"
- validatesPropositionAndTheorem
- , testCase "round-trips deterministic epoch cache values"
- roundTripsEpochCacheValues
- , testCase "validates compact fact authority"
- validatesCompactFactAuthority
- , testCase "propagates candidate safety through local claims"
- propagatesCandidateSafety
- ]
-
-ordersFoundationManifestTags :: Assertion
-ordersFoundationManifestTags = do
- let (intrinsics, rules, axioms) =
- Identity.foundationManifestTags
- assertEqual
- "intrinsic stable-tag order"
- [ Core.Member
- , Core.Empty
- , Core.PairSet
- , Core.FamilyUnion
- , Core.PowerSet
- , Core.Sep
- , Core.Repl
- , Core.SetChoose
- , Core.UnivOf
- , Core.ISetLfp
- ]
- intrinsics
- assertEqual
- "kernel-rule stable-tag order"
- [ Foundation.SetLfpBound
- , Foundation.SetLfpLeast
- , Foundation.SetLfpFixed
- , Foundation.SetLfpInduct
- ]
- rules
- assertEqual
- "foundation-axiom stable-tag order"
- [ Foundation.EmptyCharacteristic
- , Foundation.PairSetCharacteristic
- , Foundation.FamilyUnionCharacteristic
- , Foundation.PowerSetCharacteristic
- , Foundation.SeparationCharacteristic
- , Foundation.ReplacementCharacteristic
- , Foundation.SetChooseWitness
- , Foundation.SetExtensionality
- , Foundation.SetInduction
- , Foundation.PropositionalExtensionality
- , Foundation.DoubleNegationElim
- , Foundation.UnivOfContains
- , Foundation.UnivOfTransitive
- , Foundation.UnivOfFamilyUnionClosed
- , Foundation.UnivOfPowerSetClosed
- , Foundation.UnivOfReplacementClosed
- , Foundation.UnivOfMinimal
- ]
- axioms
-
-hashesCanonicalFields :: Assertion
-hashesCanonicalFields = do
- let vectors =
- [ ( []
- , "09ace37213e33d80b79e5f21fd60d03f25855e528cc2f25da4762be81d34a8c2"
- )
- , ( [ByteString.empty]
- , "cd166f5b566ebd02f00f202792699803df09e9a020afbaaa987f5001cb1d095e"
- )
- , (["a", "bc"]
- , "70c43385ae5b28bb862bc461a3c8d85ab94fd616528e7d94a9e7a52217b5c657"
- )
- , (["ab", "c"]
- , "d3588d1b26aac958d9f393d8528ad68ed34354aee41d7e405a156b3ffff20c90"
- )
- ]
- traverse_
- (\(fields, expected) -> do
- digest <- expectRight
- (hashCanonicalFields "felix-test-v1" fields)
- assertEqual
- ("fields " <> show fields)
- expected
- (mathematicalDigestHex digest))
- vectors
-
-encodesSourcePaths :: Assertion
-encodesSourcePaths = do
- let absoluteVectors =
- [ ([]
- , "000000000000002266656c69782d6162736f6c7574652d736f757263652d726f6f742d706174682d763100000000"
- )
- , (["a"]
- , "000000000000002266656c69782d6162736f6c7574652d736f757263652d726f6f742d706174682d763100000001000000000000000161"
- )
- , (["a", "b"]
- , "000000000000002266656c69782d6162736f6c7574652d736f757263652d726f6f742d706174682d763100000002000000000000000161000000000000000162"
- )
- ]
- relativeVectors =
- [ (["a"]
- , "000000000000001b66656c69782d736166652d72656c61746976652d706174682d763100000001000000000000000161"
- )
- , (["a", "b"]
- , "000000000000001b66656c69782d736166652d72656c61746976652d706174682d763100000002000000000000000161000000000000000162"
- )
- ]
- traverse_
- (\(components, expected) -> do
- encoded <- expectRight
- (encodeCanonicalPathRecord
- "felix-absolute-source-root-path-v1"
- components)
- assertEqual
- (show components)
- expected
- (hex encoded))
- absoluteVectors
- traverse_
- (\(components, expected) -> do
- encoded <- expectRight
- (encodeCanonicalPathRecord
- "felix-safe-relative-path-v1"
- components)
- assertEqual
- (show components)
- expected
- (hex encoded))
- relativeVectors
-
-separatesModuleOwnership :: Assertion
-separatesModuleOwnership =
- withTemporaryDirectory "felix-module-owner" \root -> do
- writeFile (root Posix.</> "b.tex") ""
- mounts <- expectRight
- =<< prepareSourceMounts
- [(sourceMountId "display-only", root)]
- request <- expectRight (searchedRoot "b.tex")
- source <- expectRight =<< resolveRoot mounts request
- mount <- case sourceMountList mounts of
- [only] ->
- pure only
- _ ->
- assertFailure "expected one prepared mount"
- >> fail "unreachable"
- relative <- expectRight (safeRelativePath "b.tex")
- let owner =
- moduleName (resolvedSourceAddress source)
- assertEqual
- "relative owner"
- relative
- (moduleNameRelativePath owner)
- assertEqual
- "namespace derives from the canonical root"
- (sourceNamespaceId (sourceMountRoot mount))
- (moduleNameNamespace owner)
-
-rejectsDuplicateCanonicalCollections :: Assertion
-rejectsDuplicateCanonicalCollections = do
- assertEqual
- "set duplicate"
- (Left (DuplicateCanonicalSetElement "a"))
- (encodeCanonicalSet ["b", "a", "a"])
- assertEqual
- "map duplicate"
- (Left (DuplicateCanonicalMapKey "a"))
- (encodeCanonicalMap [("a", "first"), ("a", "second")])
-
-matchesMathematicalIdentityVectors :: Assertion
-matchesMathematicalIdentityVectors = do
- fixture <- makeIdentityFixture
- let vectors =
- [ ( "theory"
- , Identity.theoryIdDigest
- (fixtureTheory fixture)
- , "46665f15f80ad52d319188de307471f34905ec3849b84b9d6d0d5a584a90eb62"
- )
- , ( "intrinsic Empty"
- , Identity.objectIdDigest
- (fixtureIntrinsic fixture)
- , "a11f641738714ac806f3c3b902841b3178d32fff38fea353aac409e3cc1a8efc"
- )
- , ( "transparent Empty"
- , Identity.objectIdDigest
- (fixtureTransparent fixture)
- , "49dfb3c96f0db2cc81703bbed82c08e9d2eda7d4a2274f0529d22c592003d4d1"
- )
- , ( "opaque signature"
- , Identity.objectIdDigest
- (fixtureOpaque fixture)
- , "8723488e60ed09ffad378bc6d9916d07c348d12d01548a7b482726e6e18b2c8d"
- )
- , ( "proposition"
- , Identity.propositionIdDigest
- (Identity.checkedPropositionId
- (fixtureProposition fixture))
- , "c40b403f0422f4125065d83b5eba64e4b0c4b24fb1559967ef986f5265829b65"
- )
- , ( "theorem"
- , Identity.theoremIdDigest
- (fixtureTheorem fixture)
- , "6a328a4142fde3c9851186ea00f54d8978d2640dcbe51421536c9726f4f717d2"
- )
- ]
- traverse_
- (\(description, digest, expected) ->
- assertEqual
- description
- expected
- (mathematicalDigestHex digest))
- vectors
- assertEqual
- "opaque declaration seed"
- "27697d641220b8bb63b32631492646277b28e70c8b7149206580337254ecc123"
- (mathematicalDigestHex
- (Identity.opaqueDeclarationSeedDigest
- (fixtureOpaqueSeed fixture)))
- assertEqual
- "family domains remain distinct"
- (length vectors)
- (Set.size
- (Set.fromList
- [ digest
- | (_description, digest, _expected) <- vectors
- ]))
-
-validatesTransparentObjectClosure :: Assertion
-validatesTransparentObjectClosure = do
- fixture <- makeIdentityFixture
- let theory = fixtureTheory fixture
- child = fixtureTransparent fixture
- parentBody = Core.CGlobal child
- parent =
- Identity.transparentObjectId
- theory
- Core.TySet
- parentBody
- assertions =
- [ Identity.assertedObject
- parent
- (Identity.TransparentObjectContent
- theory
- Core.TySet
- parentBody)
- , Identity.assertedObject
- child
- (Identity.TransparentObjectContent
- theory
- Core.TySet
- (Core.CIntrinsic Core.Empty))
- , Identity.assertedObject
- (fixtureIntrinsic fixture)
- (Identity.IntrinsicObjectContent
- theory
- Core.Empty
- Core.TySet)
- ]
- closure <- expectRight
- (Identity.validateObjectClosure theory assertions)
- assertEqual
- "all recursively checked objects"
- (Set.fromList
- [ fixtureIntrinsic fixture
- , child
- , parent
- ])
- (Identity.checkedObjectIds closure)
- assertEqual
- "parent type"
- (Just Core.TySet)
- (Identity.lookupCheckedObjectType parent closure)
-
-rejectsInvalidObjectContent :: Assertion
-rejectsInvalidObjectContent = do
- fixture <- makeIdentityFixture
- firstDigest <- expectRight
- (hashCanonicalFields "felix-invalid-object-a" [])
- secondDigest <- expectRight
- (hashCanonicalFields "felix-invalid-object-b" [])
- mismatchDigest <- expectRight
- (hashCanonicalFields "felix-invalid-object-mismatch" [])
- let theory = fixtureTheory fixture
- first =
- Identity.objectId
- Identity.TransparentObject
- firstDigest
- second =
- Identity.objectId
- Identity.TransparentObject
- secondDigest
- cycleAssertions =
- [ Identity.assertedObject
- first
- (Identity.TransparentObjectContent
- theory
- Core.TySet
- (Core.CGlobal second))
- , Identity.assertedObject
- second
- (Identity.TransparentObjectContent
- theory
- Core.TySet
- (Core.CGlobal first))
- ]
- case Identity.validateObjectClosure theory cycleAssertions of
- Left (Identity.TransparentObjectCycle path) -> do
- assertEqual
- "cycle closes"
- (NonEmpty.head path)
- (NonEmpty.last path)
- assertEqual
- "cycle members"
- (Set.fromList [first, second])
- (Set.fromList (NonEmpty.toList path))
- Left other ->
- assertFailure
- ("expected a transparent cycle, got " <> show other)
- Right _ ->
- assertFailure "expected a transparent cycle, got Right"
- let mismatched =
- Identity.objectId
- Identity.TransparentObject
- mismatchDigest
- content =
- Identity.TransparentObjectContent
- theory
- Core.TySet
- (Core.CIntrinsic Core.Empty)
- case
- Identity.validateObjectClosure
- theory
- [Identity.assertedObject mismatched content] of
- Left
- (Identity.ObjectIdPayloadMismatch
- supplied
- computed) -> do
- assertEqual "supplied ID" mismatched supplied
- assertEqual
- "computed ID"
- (fixtureTransparent fixture)
- computed
- Left other ->
- assertFailure
- ("expected object ID disagreement, got " <> show other)
- Right _ ->
- assertFailure "expected object ID disagreement, got Right"
-
-validatesPropositionAndTheorem :: Assertion
-validatesPropositionAndTheorem = do
- fixture <- makeIdentityFixture
- let proposition =
- fixtureProposition fixture
- reference =
- fixtureTheoremRef fixture
- assertEqual
- "theorem retains its theory"
- (fixtureTheory fixture)
- (Identity.theoremRefTheory reference)
- assertEqual
- "theorem retains its proposition"
- (Identity.checkedPropositionId proposition)
- (Identity.theoremRefProposition reference)
- falsum <- expectRight
- (Identity.validatePropositionContent
- (fixtureClosure fixture)
- Core.CFalsum)
- case
- Identity.validateAssertedPropositionContent
- (fixtureClosure fixture)
- (Identity.checkedPropositionId falsum)
- (Core.frozenCoreTerm
- (Identity.checkedPropositionTerm proposition)) of
- Left
- (Identity.PropositionIdPayloadMismatch
- supplied
- computed) -> do
- assertEqual
- "supplied proposition ID"
- (Identity.checkedPropositionId falsum)
- supplied
- assertEqual
- "computed proposition ID"
- (Identity.checkedPropositionId proposition)
- computed
- Left other ->
- assertFailure
- ("expected proposition ID disagreement, got "
- <> show other)
- Right _ ->
- assertFailure
- "expected proposition ID disagreement, got Right"
-
-roundTripsEpochCacheValues :: Assertion
-roundTripsEpochCacheValues = do
- fixture <- makeIdentityFixture
- let theory = fixtureTheory fixture
- contents =
- [ Identity.IntrinsicObjectContent
- theory
- Core.Empty
- Core.TySet
- , Identity.TransparentObjectContent
- theory
- Core.TySet
- (Core.CIntrinsic Core.Empty)
- , Identity.OpaqueObjectContent
- theory
- (fixtureOpaqueSeed fixture)
- Core.TySet
- ]
- traverse_
- (\content ->
- assertEqual
- "object-content cache round trip"
- (Right content)
- (decodeCache
- Identity.getObjectContentCache
- (encodeCache
- (Identity.putObjectContentCache
- content))))
- contents
- assertEqual
- "constructive theorem reference cache round trip"
- (Right (fixtureTheoremRef fixture))
- (decodeCache
- Identity.getTheoremRefCache
- (encodeCache
- (Identity.putTheoremRefCache
- (fixtureTheoremRef fixture))))
- assertBool
- "cache bytes are not mathematical theorem-reference bytes"
- ( encodeCache
- (Identity.putTheoremRefCache
- (fixtureTheoremRef fixture))
- /= Identity.encodeTheoremRef
- (fixtureTheoremRef fixture)
- )
- let ascending =
- Map.fromList [("a", 1 :: Natural), ("b", 2)]
- putMap =
- putCanonicalCacheMap
- putCacheText
- putCacheNatural
- assertEqual
- "canonical cache map round trip"
- (Right ascending)
- (decodeCache
- (getCanonicalCacheMap
- getCacheText
- getCacheNatural)
- (encodeCache (putMap ascending)))
-
-validatesCompactFactAuthority :: Assertion
-validatesCompactFactAuthority = do
- fixture <- makeIdentityFixture
- let reference = fixtureTheoremRef fixture
- sourceKinds =
- Authority.singletonEscapeKind Authority.SourceAxiom
- bothKinds =
- Authority.escapeKinds
- [Authority.Omitted, Authority.SourceAxiom]
- sourceTarget =
- Authority.factAuthority
- reference
- (Authority.authoritySafety sourceKinds)
- bothTarget =
- Authority.factAuthority
- reference
- (Authority.authoritySafety bothKinds)
- requests =
- [ Authority.preparedRequestId
- Authority.PreparedRequestFof
- Authority.PreparedRequestDirect
- "first"
- , Authority.preparedRequestId
- Authority.PreparedRequestFof
- Authority.PreparedRequestDirect
- "first"
- , Authority.preparedRequestId
- Authority.PreparedRequestFof
- Authority.PreparedRequestDirect
- "second"
- ]
- directRequest =
- Authority.preparedRequestId
- Authority.PreparedRequestFof
- Authority.PreparedRequestDirect
- "same bytes"
- indirectRequest =
- Authority.preparedRequestId
- Authority.PreparedRequestFof
- Authority.PreparedRequestIndirect
- "same bytes"
- directAuthorizations =
- [ Authority.CheckedKernelConstruction
- (Authority.FoundationLeaf
- Foundation.EmptyCharacteristic)
- , Authority.CheckedKernelConstruction
- (Authority.GuardedFoundationRules
- (Authority.guardedRuleSet
- (Foundation.SetLfpBound :| [])))
- , Authority.CheckedKernelConstruction
- (Authority.CheckedDefinitionEquation
- (fixtureIntrinsic fixture))
- , Authority.CheckedKernelConstruction
- (Authority.CheckedSetConstructionExtensionality
- (fixtureIntrinsic fixture)
- (hashCacheFields
- "test-named-construction" ["checked"]))
- , Authority.CheckedSourceProof requests
- , Authority.TrustedCompilation
- (Authority.DatatypeCompilation
- (Authority.datatypeCompilationDescriptor
- (fixtureIntrinsic fixture)
- (NonEmpty.singleton
- (fixtureIntrinsic fixture))
- [reference]))
- , Authority.SourceAxiomAuthorization
- , Authority.OmittedAuthorization
- ]
- sourceCertificate <- expectRight
- (Authority.validationCertificate
- sourceTarget
- Authority.SourceAxiomAuthorization)
- proofCertificate <- expectRight
- (Authority.validationCertificate
- bothTarget
- (Authority.CheckedSourceProof requests))
- assertEqual
- "escape bits have canonical order"
- [Authority.SourceAxiom, Authority.Omitted]
- (Authority.escapeKindsToList bothKinds)
- traverse_
- (\direct ->
- assertEqual
- ("direct authorization round trip: " <> show direct)
- (Right direct)
- (decodeCache
- Authority.getDirectAuthorizationCache
- (encodeCache
- (Authority.putDirectAuthorizationCache
- direct))))
- directAuthorizations
- assertEqual
- "certificate cache retains repeated ordered requests"
- (Right proofCertificate)
- (decodeCache
- Authority.getValidationCertificateCache
- (encodeCache
- (Authority.putValidationCertificateCache
- proofCertificate)))
- assertBool
- "request mode participates in exact request identity"
- (directRequest /= indirectRequest)
- assertEqual
- "prepared-request cache identity vector"
- "1d72b851cb8b1704617becbf9f2cf492aed1c674d9e6ca759e244f169b15f278"
- (hex
- (encodeCache
- (Authority.putPreparedRequestIdCache
- directRequest)))
- assertEqual
- "source certificate round trip"
- (Right sourceCertificate)
- (decodeCache
- Authority.getValidationCertificateCache
- (encodeCache
- (Authority.putValidationCertificateCache
- sourceCertificate)))
- assertBool
- "source axiom requires its exact singleton safety"
- (isLeft
- (Authority.validationCertificate
- bothTarget
- Authority.SourceAxiomAuthorization))
- assertBool
- "omitted authorization requires its distinct bit"
- (isLeft
- (Authority.validationCertificate
- sourceTarget
- Authority.OmittedAuthorization))
- assertBool
- "cache rejects an empty escape-backed value"
- (isLeft
- (decodeCache
- Authority.getAuthoritySafetyCache
- (encodeCache do
- putCacheTag 0x01
- putCacheTag 0x00)))
- let taintedCandidate =
- Authority.addCandidateEscape
- Authority.SourceAxiom
- Authority.initialCandidateSafety
- assertEqual
- "candidate completion freezes accumulated safety"
- sourceTarget
- (Authority.candidateFactAuthority
- reference
- taintedCandidate)
-
-propagatesCandidateSafety :: Assertion
-propagatesCandidateSafety = do
- fixture <- makeIdentityFixture
- let reference = fixtureTheoremRef fixture
- imported =
- Authority.factAuthority
- reference
- (Authority.authoritySafety
- (Authority.singletonEscapeKind
- Authority.SourceAxiom))
- afterImported <- expectRight
- (Authority.accumulateFactSafety
- reference
- imported
- Authority.initialCandidateSafety)
- -- A local claim shares the enclosing candidate value; citing that claim
- -- does not create a second support representation.
- afterLocalClaim <- expectRight
- (Authority.accumulateFactSafety
- reference
- (Authority.factAuthority
- reference
- Authority.cleanAuthoritySafety)
- afterImported)
- let finalSafety =
- Authority.addCandidateEscape
- Authority.Omitted
- afterLocalClaim
- assertEqual
- "local claim retains prior safety and direct omission"
- [Authority.SourceAxiom, Authority.Omitted]
- (Authority.escapeKindsToList
- (Authority.authoritySafetyEscapeKinds
- (Authority.candidateSafetyAuthority finalSafety)))
-
-data IdentityFixture = IdentityFixture
- { fixtureTheory :: !Identity.TheoryId
- , fixtureIntrinsic :: !Identity.ObjectId
- , fixtureTransparent :: !Identity.ObjectId
- , fixtureOpaqueSeed :: !Identity.OpaqueDeclarationSeed
- , fixtureOpaque :: !Identity.ObjectId
- , fixtureClosure :: !Identity.CheckedObjectClosure
- , fixtureProposition :: !Identity.CheckedPropositionContent
- , fixtureTheoremRef :: !Identity.TheoremRef
- , fixtureTheorem :: !Identity.TheoremId
- }
-
-makeIdentityFixture :: IO IdentityFixture
-makeIdentityFixture = do
- foundation <- expectRight Foundation.checkedFoundation
- pathRecord <- expectRight
- (encodeCanonicalPathRecord
- "felix-absolute-source-root-path-v1"
- ["a"])
- namespaceDigest <- expectRight
- (hashCanonicalFields
- "felix-source-namespace-v1"
- [pathRecord])
- relative <- expectRight (safeRelativePath "b.tex")
- let theory =
- Identity.theoryId foundation
- intrinsic =
- Identity.intrinsicObjectId
- theory
- Core.Empty
- Core.TySet
- transparent =
- Identity.transparentObjectId
- theory
- Core.TySet
- (Core.CIntrinsic Core.Empty)
- owner =
- moduleNameFromParts
- (sourceNamespaceIdFromDigest
- namespaceDigest)
- relative
- seed =
- Identity.opaqueDeclarationSeed
- owner
- (localDeclarationOrdinal 2)
- SignatureDeclaration
- (generatedObjectSlot 0)
- opaque =
- Identity.opaqueObjectId
- theory
- seed
- Core.TySet
- closure <- expectRight
- (Identity.validateObjectClosure
- theory
- [ Identity.assertedObject
- intrinsic
- (Identity.IntrinsicObjectContent
- theory
- Core.Empty
- Core.TySet)
- ])
- proposition <- expectRight
- (Identity.validatePropositionContent
- closure
- (Core.CEq
- Core.TySet
- (Core.CGlobal intrinsic)
- (Core.CGlobal intrinsic)))
- let reference =
- Identity.theoremRef
- theory
- (Identity.checkedPropositionId proposition)
- pure
- IdentityFixture
- { fixtureTheory = theory
- , fixtureIntrinsic = intrinsic
- , fixtureTransparent = transparent
- , fixtureOpaqueSeed = seed
- , fixtureOpaque = opaque
- , fixtureClosure = closure
- , fixtureProposition = proposition
- , fixtureTheoremRef = reference
- , fixtureTheorem =
- Identity.theoremId reference
- }
-
-hex :: ByteString.ByteString -> Text
-hex =
- Text.pack
- . concatMap byteHex
- . ByteString.unpack
- where
- byteHex byte =
- let digits = "0123456789abcdef"
- high = fromIntegral (byte `div` 16)
- low = fromIntegral (byte `mod` 16)
- in [digits `at` high, digits `at` low]
-
- at characters index =
- fromMaybe
- (impossible "hex digit index")
- (nth index characters)
-
-expectRight :: Show error => Either error value -> IO value
-expectRight = \case
- Left err ->
- assertFailure (show err) >> fail "unreachable"
- Right value ->
- pure value
-
-withTemporaryDirectory :: String -> (FilePath -> IO a) -> IO a
-withTemporaryDirectory template =
- bracket create Directory.removePathForcibly
- where
- create = do
- systemTemp <- Directory.getTemporaryDirectory
- (path, handle) <- openTempFile systemTemp template
- hClose handle
- Directory.removeFile path
- Directory.createDirectory path
- pure path
diff --git a/source/Test/Unit/Kernel.hs b/source/Test/Unit/Kernel.hs
deleted file mode 100644
index d01a194..0000000
--- a/source/Test/Unit/Kernel.hs
+++ /dev/null
@@ -1,858 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE PatternSynonyms #-}
-
-module Test.Unit.Kernel (unitTests) where
-
-import Base hiding (Empty)
-import Checking.Core
-import Checking.Foundation qualified as Foundation
-import Checking.Kernel.Derivation
-import Checking.Kernel.Semantics qualified as Semantics
-import Checking.Kernel.SetLfp qualified as SetLfp
-import Checking.Typed.Inductive qualified as Inductive
-import Report.Location (pattern Nowhere)
-import Syntax.Internal qualified as Internal
-
-import Data.Set qualified as Set
-import Data.Vector qualified as Vector
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-data TestGlobal = TestGlobal
- deriving (Show, Eq, Ord)
-
-testGlobalType :: TestGlobal -> CoreType
-testGlobalType _global = TySet
-
-unitTests :: TestTree
-unitTests =
- testGroup "Kernel replay"
- [ testCase
- "replays equality reflexivity through kernel semantics"
- replaysEqualityReflexivity
- , testCase
- "replays logical scopes and elimination"
- replaysLogicalScopes
- , testCase
- "replays quantifier and equality structure"
- replaysQuantifierAndEqualityStructure
- , testCase
- "records foundation and import leaves"
- recordsAuthorityLeaves
- , testCase
- "checks and replays the exact set fixed-point rules"
- checksSetLfpRules
- , testCase
- "replays direct inductive facts"
- replaysDirectInductiveFacts
- , testCase
- "rejects altered set fixed-point applications"
- rejectsAlteredSetLfpApplications
- , testCase
- "rejects invalid scoped replay"
- rejectsInvalidScopedReplay
- , testCase
- "rejects a caller-supplied target mismatch"
- rejectsTargetMismatch
- ]
-
-replaysEqualityReflexivity :: Assertion
-replaysEqualityReflexivity = do
- foundation <-
- expectRight Foundation.checkedFoundation
- operand <-
- expectRight
- (checkCanonicalCore
- absurd
- (CIntrinsic Empty))
- direct <-
- expectRight
- (Semantics.equalityReflexivity
- absurd
- (embedClosedCore [] operand))
- directClosed <-
- maybe
- (assertFailure
- "closed reflexivity result remained scoped")
- pure
- (closeScopedCore direct)
- replayed <-
- expectRight
- (replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- absurd
- Vector.empty
- directClosed
- (equalityReflexivityDerivation operand))
- assertEqual
- "replay agrees with direct semantics"
- directClosed
- (replayedKernelTarget replayed)
- assertEqual
- "one replayed inference"
- 1
- (replayedKernelNodeCount replayed)
-
-replaysLogicalScopes :: Assertion
-replaysLogicalScopes = do
- foundation <-
- expectRight Foundation.checkedFoundation
- proposition <-
- checkedClosed
- (CEq TySet
- (CIntrinsic Empty)
- (CIntrinsic Empty))
- implication <-
- checkedScoped []
- (CImp
- (frozenCoreTerm proposition)
- (frozenCoreTerm proposition))
- let propositionScoped =
- embedClosedCore [] proposition
- identity =
- implicationIntroductionDerivation
- propositionScoped
- (localHypothesisDerivation
- (hypothesisIx 0))
- elimination =
- implicationIntroductionDerivation
- propositionScoped
- (implicationIntroductionDerivation
- implication
- (implicationEliminationDerivation
- (localHypothesisDerivation
- (hypothesisIx 0))
- (localHypothesisDerivation
- (hypothesisIx 1))))
- fromFalsum =
- implicationIntroductionDerivation
- falsum
- (falsumEliminationDerivation
- (localHypothesisDerivation
- (hypothesisIx 0))
- propositionScoped)
- falsum =
- unsafeScoped [] CFalsum
- assertReplayTarget
- foundation
- (CImp
- (frozenCoreTerm proposition)
- (frozenCoreTerm proposition))
- identity
- assertReplayTarget
- foundation
- (CImp
- (frozenCoreTerm proposition)
- (CImp
- (scopedCoreTerm implication)
- (frozenCoreTerm proposition)))
- elimination
- assertReplayTarget
- foundation
- (CImp
- CFalsum
- (frozenCoreTerm proposition))
- fromFalsum
-
-replaysQuantifierAndEqualityStructure :: Assertion
-replaysQuantifierAndEqualityStructure = do
- foundation <-
- expectRight Foundation.checkedFoundation
- boundSet <-
- checkedScoped [TySet] (CBound 0)
- emptySet <-
- checkedScoped [] (CIntrinsic Empty)
- unionFunction <-
- checkedScoped [] (CIntrinsic FamilyUnion)
- proposition <-
- checkedClosed
- (CEq TySet
- (CIntrinsic Empty)
- (CIntrinsic Empty))
- convertedTarget <-
- checkedScoped []
- (CEq TySet
- (CApp
- (CLam TySet (CBound 0))
- (CIntrinsic Empty))
- (CIntrinsic Empty))
- oneReduction <-
- expectRight (conversionPlan 1)
- let boundReflexivity =
- scopedEqualityReflexivityDerivation boundSet
- universalReflexivity =
- forallIntroductionDerivation
- TySet
- boundReflexivity
- specializedReflexivity =
- forallEliminationDerivation
- universalReflexivity
- emptySet
- applicationCongruence =
- equalityCongruenceApplicationDerivation
- (scopedEqualityReflexivityDerivation
- unionFunction)
- (scopedEqualityReflexivityDerivation
- emptySet)
- lambdaCongruence =
- equalityCongruenceLambdaDerivation
- TySet
- boundReflexivity
- equalityMp =
- implicationIntroductionDerivation
- (embedClosedCore [] proposition)
- (equalityModusPonensDerivation
- (scopedEqualityReflexivityDerivation
- (embedClosedCore []
- proposition))
- (localHypothesisDerivation
- (hypothesisIx 0)))
- conversion =
- convertJudgmentDerivation
- (scopedEqualityReflexivityDerivation
- emptySet)
- convertedTarget
- oneReduction
- assertReplayTarget
- foundation
- (CForall TySet
- (CEq TySet
- (CBound 0)
- (CBound 0)))
- universalReflexivity
- assertReplayTarget
- foundation
- (CEq TySet
- (CIntrinsic Empty)
- (CIntrinsic Empty))
- specializedReflexivity
- assertReplayTarget
- foundation
- (CEq TySet
- (CApp
- (CIntrinsic FamilyUnion)
- (CIntrinsic Empty))
- (CApp
- (CIntrinsic FamilyUnion)
- (CIntrinsic Empty)))
- applicationCongruence
- assertReplayTarget
- foundation
- (CEq
- (TySet `TyArrow` TySet)
- (CLam TySet (CBound 0))
- (CLam TySet (CBound 0)))
- lambdaCongruence
- assertReplayTarget
- foundation
- (CImp
- (frozenCoreTerm proposition)
- (frozenCoreTerm proposition))
- equalityMp
- assertReplayTarget
- foundation
- (scopedCoreTerm convertedTarget)
- conversion
-
-recordsAuthorityLeaves :: Assertion
-recordsAuthorityLeaves = do
- foundation <-
- expectRight Foundation.checkedFoundation
- let foundationTag =
- Foundation.EmptyCharacteristic
- foundationTarget =
- mapFrozenGlobals
- absurd
- (Foundation.foundationAxiomFrozen
- foundation
- foundationTag)
- foundationReplay <-
- expectRight
- (replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- absurd
- Vector.empty
- foundationTarget
- (foundationFactDerivation
- foundationTag))
- assertEqual
- "exact foundation use"
- (Set.singleton foundationTag)
- (replayedKernelFoundationUses
- foundationReplay)
- importedStatement <-
- checkedClosed
- (CEq TySet
- (CIntrinsic Empty)
- (CIntrinsic Empty))
- importedJudgment <-
- expectRight
- (derivationImportJudgment
- importedStatement)
- importedReplay <-
- expectRight
- (replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- absurd
- (Vector.singleton importedJudgment)
- importedStatement
- (importedFactDerivation
- (importIx 0)))
- assertEqual
- "exact import use"
- (Set.singleton (importIx 0))
- (replayedKernelImportUses importedReplay)
-
-checksSetLfpRules :: Assertion
-checksSetLfpRules = do
- foundation <-
- expectRight Foundation.checkedFoundation
- ( domain
- , operator
- , predicate
- , element
- , fixedPoint
- , closedPremise
- , boundedPremise
- , monotonePremise
- , memberPremise
- , closurePremise
- ) <-
- setLfpFixture
- bound <-
- expectRight
- (SetLfp.setLfpBound
- foundation
- absurd
- domain
- operator)
- least <-
- expectRight
- (SetLfp.setLfpLeast
- foundation
- absurd
- domain
- operator
- domain
- closedPremise
- boundedPremise)
- fixed <-
- expectRight
- (SetLfp.setLfpFixed
- foundation
- absurd
- domain
- operator
- monotonePremise)
- inducted <-
- expectRight
- (SetLfp.setLfpInduct
- foundation
- absurd
- domain
- operator
- predicate
- element
- monotonePremise
- memberPremise
- closurePremise)
- expectedSubset <-
- expectRight
- (SetLfp.subsetProposition
- absurd
- fixedPoint
- domain)
- expectedFixed <-
- checkedScoped []
- (CEq TySet
- (scopedCoreTerm fixedPoint)
- (CApp
- (scopedCoreTerm operator)
- (scopedCoreTerm fixedPoint)))
- expectedPredicate <-
- checkedScoped []
- (CApp
- (scopedCoreTerm predicate)
- (scopedCoreTerm element))
- assertEqual "bound conclusion" expectedSubset bound
- assertEqual "least conclusion" expectedSubset least
- assertEqual "fixed conclusion" expectedFixed fixed
- assertEqual "induction conclusion" expectedPredicate inducted
-
- target <-
- maybe
- (assertFailure
- "closed fixed-point bound remained scoped")
- pure
- (closeScopedCore bound)
- replayed <-
- expectRight
- (replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- absurd
- Vector.empty
- target
- (setLfpBoundDerivation
- domain
- operator))
- assertEqual
- "exact guarded-rule use"
- (Set.singleton Foundation.SetLfpBound)
- (replayedKernelRuleUses replayed)
-
-replaysDirectInductiveFacts :: Assertion
-replaysDirectInductiveFacts = do
- foundation <-
- expectRight Foundation.checkedFoundation
- traverse_
- (replayInductive foundation)
- [ Inductive.DirectInductive
- []
- (Internal.EmptySet Nowhere)
- (Inductive.DirectInductiveClause
- []
- []
- (Internal.EmptySet Nowhere)
- :| [])
- , let x = Internal.NamedVar "x"
- in Inductive.DirectInductive
- []
- (Internal.EmptySet Nowhere)
- ( Inductive.DirectInductiveClause
- []
- []
- (Internal.EmptySet Nowhere)
- :| [ Inductive.DirectInductiveClause
- [x]
- [Inductive.DirectRecursiveCondition
- (Internal.TermVar x)
- (Inductive.directRecursiveCarrierContext Nowhere)]
- (Internal.TermVar x)
- ]
- )
- ]
- where
- replayInductive foundation inductive = do
- prepared <-
- expectRight
- (Inductive.prepareTypedInductive
- testGlobalType
- foundation
- (const Nothing)
- (Internal.Marker "direct_inductive")
- inductive)
- imports <-
- traverse
- (expectRight . derivationImportJudgment)
- (Inductive.typedInductiveGuardTargets
- prepared)
- traverse_
- (\fact -> do
- replayed <-
- expectRight
- (replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- (const Nothing)
- imports
- (Inductive.typedInductiveFactTarget
- fact)
- (Inductive.typedInductiveFactDerivation
- fact))
- assertEqual
- "replay target"
- (Inductive.typedInductiveFactTarget
- fact)
- (replayedKernelTarget replayed))
- (Inductive.typedInductiveFacts
- prepared)
-
-rejectsAlteredSetLfpApplications :: Assertion
-rejectsAlteredSetLfpApplications = do
- foundation <-
- expectRight Foundation.checkedFoundation
- ( domain
- , operator
- , predicate
- , _element
- , _fixedPoint
- , _closedPremise
- , boundedPremise
- , _monotonePremise
- , _memberPremise
- , _closurePremise
- ) <-
- setLfpFixture
- falsum <-
- checkedScoped [] CFalsum
- assertEqual
- "altered leastness premise"
- (Left
- (SetLfp.SetLfpRulePremiseMismatch
- Foundation.SetLfpLeast
- 0))
- (SetLfp.setLfpLeast
- foundation
- absurd
- domain
- operator
- domain
- falsum
- boundedPremise)
- assertEqual
- "operator type mismatch"
- (Left
- (SetLfp.SetLfpRuleArgumentTypeMismatch
- Foundation.SetLfpBound
- 1
- (TySet `TyArrow` TySet)
- (TySet `TyArrow` TyProp)))
- (SetLfp.setLfpBound
- foundation
- absurd
- domain
- predicate)
- bound <-
- expectRight
- (SetLfp.setLfpBound
- foundation
- absurd
- domain
- operator)
- wrongTarget <-
- checkedClosed CFalsum
- assertEqual
- "altered replay target"
- (Left KernelReplayTargetMismatch)
- (replayedKernelTarget
- <$> replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- absurd
- Vector.empty
- wrongTarget
- (setLfpBoundDerivation
- domain
- operator))
- assertEqual
- "the direct bound remains well formed"
- TyProp
- (scopedCoreType bound)
-
-setLfpFixture
- :: IO
- ( ScopedCheckedCore Void
- , ScopedCheckedCore Void
- , ScopedCheckedCore Void
- , ScopedCheckedCore Void
- , ScopedCheckedCore Void
- , ScopedCheckedCore Void
- , ScopedCheckedCore Void
- , ScopedCheckedCore Void
- , ScopedCheckedCore Void
- , ScopedCheckedCore Void
- )
-setLfpFixture = do
- domain <-
- checkedScoped [] (CIntrinsic Empty)
- operator <-
- checkedScoped []
- (CLam TySet (CBound 0))
- predicate <-
- checkedScoped []
- (CLam TySet
- (CEq TySet
- (CBound 0)
- (CBound 0)))
- element <-
- checkedScoped [] (CIntrinsic Empty)
- fixedPoint <-
- expectRight
- (SetLfp.setLfpTerm
- absurd
- domain
- operator)
- operatorDomain <-
- checkedScoped []
- (CApp
- (scopedCoreTerm operator)
- (scopedCoreTerm domain))
- closedPremise <-
- expectRight
- (SetLfp.subsetProposition
- absurd
- operatorDomain
- domain)
- boundedPremise <-
- expectRight
- (SetLfp.subsetProposition
- absurd
- domain
- domain)
- monotonePremise <-
- expectRight
- (SetLfp.boundedMonoProposition
- absurd
- domain
- operator)
- memberPremise <-
- expectRight
- (SetLfp.memberProposition
- absurd
- element
- fixedPoint)
- closurePremise <-
- expectRight
- (SetLfp.inductionClosureProposition
- absurd
- domain
- operator
- predicate)
- pure
- ( domain
- , operator
- , predicate
- , element
- , fixedPoint
- , closedPremise
- , boundedPremise
- , monotonePremise
- , memberPremise
- , closurePremise
- )
-
-rejectsInvalidScopedReplay :: Assertion
-rejectsInvalidScopedReplay = do
- foundation <-
- expectRight Foundation.checkedFoundation
- proposition <-
- checkedClosed
- (CEq TySet
- (CIntrinsic Empty)
- (CIntrinsic Empty))
- boundSet <-
- checkedScoped [TySet] (CBound 0)
- assertEqual
- "missing local hypothesis"
- (Left
- (KernelReplayHypothesisOutOfBounds
- (hypothesisIx 0)))
- (replayedKernelTarget
- <$> replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- absurd
- Vector.empty
- proposition
- (localHypothesisDerivation
- (hypothesisIx 0)))
- assertEqual
- "stored term from another lexical context"
- (Left
- (KernelReplayStoredContextMismatch
- []
- [TySet]))
- (replayedKernelTarget
- <$> replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- absurd
- Vector.empty
- proposition
- (scopedEqualityReflexivityDerivation
- boundSet))
- expanded <-
- checkedScoped []
- (CEq TySet
- (CApp
- (CLam TySet (CBound 0))
- (CIntrinsic Empty))
- (CIntrinsic Empty))
- noReductions <-
- expectRight (conversionPlan 0)
- assertEqual
- "conversion budget"
- (Left
- (KernelReplaySemanticsError
- Semantics.KernelConversionBudgetExhausted))
- (replayedKernelTarget
- <$> replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- absurd
- Vector.empty
- (unsafeClosed
- (scopedCoreTerm expanded))
- (convertJudgmentDerivation
- (equalityReflexivityDerivation
- (unsafeClosed
- (CIntrinsic Empty)))
- expanded
- noReductions))
- let checkedAsSet _global =
- Just TySet
- replayedAsProposition _global =
- Just TyProp
- globalTarget <-
- expectRight
- (checkCanonicalCore
- checkedAsSet
- (CEq TySet
- (CGlobal TestGlobal)
- (CGlobal TestGlobal)))
- assertEqual
- "stored global types are rechecked"
- (Left
- (KernelReplayStoredTermIllTyped
- (EqualityOperandTypeMismatch
- TySet
- TyProp)))
- (replayedKernelTarget
- <$> replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- replayedAsProposition
- Vector.empty
- globalTarget
- (equalityReflexivityDerivation
- (unsafeGlobalOperand
- checkedAsSet)))
- oneNode <-
- expectRight (kernelReplayLimits 1 10)
- let propositionScoped =
- embedClosedCore [] proposition
- identityTarget =
- unsafeClosed
- (CImp
- (frozenCoreTerm proposition)
- (frozenCoreTerm proposition))
- assertEqual
- "replay node limit"
- (Left
- (KernelReplayNodeLimitExceeded 1))
- (replayedKernelTarget
- <$> replayKernelDerivation
- foundation
- oneNode
- absurd
- Vector.empty
- identityTarget
- (implicationIntroductionDerivation
- propositionScoped
- (localHypothesisDerivation
- (hypothesisIx 0))))
-
-rejectsTargetMismatch :: Assertion
-rejectsTargetMismatch = do
- foundation <-
- expectRight Foundation.checkedFoundation
- operand <-
- expectRight
- (checkCanonicalCore
- absurd
- (CIntrinsic Empty))
- wrongTarget <-
- expectRight
- (checkCanonicalCore
- absurd
- (CImp CFalsum CFalsum))
- assertEqual
- "the expected target is comparison input, not evidence"
- (Left KernelReplayTargetMismatch)
- (replayedKernelTarget
- <$> replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- absurd
- Vector.empty
- wrongTarget
- (equalityReflexivityDerivation operand))
-
-assertReplayTarget
- :: Foundation.CheckedFoundation
- -> CanonicalTerm Void
- -> KernelDerivation Void
- -> Assertion
-assertReplayTarget foundation expectedTerm derivation = do
- expected <-
- checkedClosed expectedTerm
- replayed <-
- expectRight
- (replayKernelDerivation
- foundation
- defaultKernelReplayLimits
- absurd
- Vector.empty
- expected
- derivation)
- assertEqual
- "replayed exact target"
- expected
- (replayedKernelTarget replayed)
-
-checkedClosed
- :: CanonicalTerm Void
- -> IO (FrozenCheckedCore Void)
-checkedClosed =
- expectRight . checkCanonicalCore absurd
-
-checkedScoped
- :: [CoreType]
- -> CanonicalTerm Void
- -> IO (ScopedCheckedCore Void)
-checkedScoped context =
- expectRight
- . checkScopedCanonicalCore absurd context
-
-unsafeScoped
- :: [CoreType]
- -> CanonicalTerm Void
- -> ScopedCheckedCore Void
-unsafeScoped context term =
- case checkScopedCanonicalCore absurd context term of
- Left coreError ->
- impossible
- ("invalid static kernel fixture: "
- <> show coreError)
- Right checked ->
- checked
-
-unsafeClosed
- :: CanonicalTerm Void
- -> FrozenCheckedCore Void
-unsafeClosed term =
- case checkCanonicalCore absurd term of
- Left coreError ->
- impossible
- ("invalid static closed kernel fixture: "
- <> show coreError)
- Right checked ->
- checked
-
-unsafeGlobalOperand
- :: (TestGlobal -> Maybe CoreType)
- -> FrozenCheckedCore TestGlobal
-unsafeGlobalOperand globalType =
- case checkCanonicalCore
- globalType
- (CGlobal TestGlobal) of
- Left coreError ->
- impossible
- ("invalid static global kernel fixture: "
- <> show coreError)
- Right checked ->
- checked
-
-expectRight
- :: Show error
- => Either error value
- -> IO value
-expectRight =
- either
- (assertFailure . show)
- pure
diff --git a/source/Test/Unit/Lexicon.hs b/source/Test/Unit/Lexicon.hs
deleted file mode 100644
index 54b4bd4..0000000
--- a/source/Test/Unit/Lexicon.hs
+++ /dev/null
@@ -1,333 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module Test.Unit.Lexicon (unitTests) where
-
-import Base
-import Felix.Cache.Codec
-import Syntax.Abstract
-import Syntax.Interface
-import Syntax.Lexicon
-
-import Data.Set qualified as Set
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "Lexicon"
- [ testCase "retains the literal ten-row base mixfix grouping"
- retainsBaseMixfixGrouping
- , testCase "checks literal mixfix levels"
- checksMixfixLevels
- , testCase "coalesces equal canonical syntax entries"
- coalescesCanonicalEntries
- , testCase "rejects shared plural parser surfaces"
- rejectsSharedPluralSurfaces
- , testCase "round-trips complete canonical lexical entries"
- roundTripsCanonicalEntries
- , testCase "round-trips asserted module syntax interfaces"
- roundTripsSyntaxInterfaces
- ]
-
-retainsBaseMixfixGrouping :: Assertion
-retainsBaseMixfixGrouping =
- do
- assertEqual
- "least-to-most-tight marker and associativity rows"
- expectedBaseRows
- (fmap (fmap entryShape) builtinMixfixLevels)
- assertEqual
- "canonical base manifest"
- expectedBaseRows
- (fmap (fmap canonicalEntryShape) baseSyntaxManifest)
- assertEqual
- "cache-epoch base syntax identity"
- "97acdc8153821b20dd0f45cf9d44870705723bb60737f7bacbb9ac31a98987a5"
- (cacheDigestHex
- (baseSyntaxInterfaceIdDigest
- baseSyntaxInterfaceId))
- where
- entryShape (MixfixItem _pattern marker associativity) =
- (marker, associativity)
-
- canonicalEntryShape = \case
- CanonicalExpressionFunction
- _pattern
- marker
- (Fixity associativity _level) ->
- (marker, associativity)
- entry ->
- impossible
- ("non-expression entry in base manifest: "
- <> show entry)
-
-checksMixfixLevels :: Assertion
-checksMixfixLevels = do
- assertEqual
- "lowest level"
- (Right 0)
- (mixfixLevelValue <$> mixfixLevel 0)
- assertEqual
- "highest internal level"
- (Right 9)
- (mixfixLevelValue <$> mixfixLevel 9)
- assertEqual
- "out-of-range level"
- (Left (MixfixLevelOutOfRange 10))
- (mixfixLevel 10)
-
-coalescesCanonicalEntries :: Assertion
-coalescesCanonicalEntries = do
- level <- expectRight (mixfixLevel 3)
- let pat =
- patternFromHoley
- [ Nothing
- , Just (Command "star")
- , Nothing
- ]
- first =
- CanonicalExpressionFunction
- pat
- "star"
- (Fixity LeftAssoc level)
- conflicting =
- CanonicalExpressionFunction
- pat
- "other_star"
- (Fixity LeftAssoc level)
- delta <- expectRight
- (canonicalSyntaxDelta [first, first])
- assertEqual
- "equal entries coalesce"
- 1
- (canonicalSyntaxDeltaSize delta)
- assertEqual
- "coalesced entry"
- [first]
- (canonicalSyntaxDeltaEntries delta)
- assertEqual
- "collision is independent of occurrence order"
- (canonicalSyntaxDelta [first, conflicting])
- (canonicalSyntaxDelta [conflicting, first])
-
-rejectsSharedPluralSurfaces :: Assertion
-rejectsSharedPluralSurfaces = do
- let nounEntry =
- CanonicalNoun
- (wordPattern "member")
- (wordPattern "objects")
- "member"
- otherNoun =
- CanonicalNoun
- (wordPattern "element")
- (wordPattern "objects")
- "element"
- verbEntry =
- CanonicalVerb
- (wordPattern "belongs")
- (wordPattern "objects")
- "belongs"
- assertPluralCollision nounEntry otherNoun
- assertPluralCollision nounEntry verbEntry
- case decodeCache
- getCanonicalSyntaxDeltaCache
- (encodeCache
- (putCacheList
- putCanonicalLexicalEntryCache
- [nounEntry, otherNoun])) of
- Left _ ->
- pure ()
- Right _ ->
- assertFailure
- "decoded a delta with a shared plural collision"
- where
- wordPattern word =
- TokenCons (Word word) End
-
- assertPluralCollision first second =
- case canonicalSyntaxDelta [first, second] of
- Left collision -> do
- assertEqual
- "shared plural pattern"
- (wordPattern "objects")
- (canonicalCollisionPattern collision)
- assertEqual
- "both complete entries"
- (Set.fromList [first, second])
- (Set.fromList
- (toList
- (canonicalCollisionEntries collision)))
- Right _ ->
- assertFailure
- "accepted two entries with one parser-active plural"
-
-roundTripsCanonicalEntries :: Assertion
-roundTripsCanonicalEntries = do
- level <- expectRight (mixfixLevel 4)
- let unary =
- patternFromHoley
- [ Just (Word "red")
- , Nothing
- ]
- singular =
- patternFromHoley
- [ Just (Word "member")
- , Just (Word "of")
- , Nothing
- ]
- plural =
- patternFromHoley
- [ Just (Word "members")
- , Just (Word "of")
- , Nothing
- ]
- binary =
- patternFromHoley
- [ Nothing
- , Just (Command "star")
- , Nothing
- ]
- entries =
- [ CanonicalLeftAdjective unary "red"
- , CanonicalRightAdjective unary "red_right"
- , CanonicalFunctionPhrase singular plural "member_fun"
- , CanonicalNoun singular plural "member"
- , CanonicalStructureNoun singular plural "member_struct"
- , CanonicalVerb singular plural "member_verb"
- , CanonicalRelation (Command "rel") (ParameterArity 2) "rel"
- , CanonicalExpressionFunction
- binary
- "star"
- (Fixity LeftAssoc level)
- , CanonicalPrefixPredicate "Pred" 3 "pred"
- , CanonicalStructureOperation "operation"
- ]
- traverse_
- (\entry ->
- assertEqual
- ("cache round trip for " <> show entry)
- (Right entry)
- (decodeCache
- getCanonicalLexicalEntryCache
- (encodeCache
- (putCanonicalLexicalEntryCache entry))))
- entries
-
-roundTripsSyntaxInterfaces :: Assertion
-roundTripsSyntaxInterfaces = do
- level <- expectRight (mixfixLevel 7)
- changedLevel <- expectRight (mixfixLevel 6)
- let entry =
- CanonicalExpressionFunction
- (patternFromHoley
- [ Nothing
- , Just (Command "diamond")
- , Nothing
- ])
- "diamond"
- (Fixity NonAssoc level)
- changedEntry =
- CanonicalExpressionFunction
- (patternFromHoley
- [ Nothing
- , Just (Command "diamond")
- , Nothing
- ])
- "diamond"
- (Fixity RightAssoc changedLevel)
- delta <- expectRight (canonicalSyntaxDelta [entry])
- changedDelta <- expectRight
- (canonicalSyntaxDelta [changedEntry])
- interface <- expectRight
- (moduleSyntaxInterface [] delta)
- changedInterface <- expectRight
- (moduleSyntaxInterface [] changedDelta)
- assertEqual
- "current fixed base"
- baseSyntaxInterfaceId
- (moduleSyntaxBase interface)
- assertEqual
- "module syntax cache round trip"
- (Right interface)
- (decodeCache
- getModuleSyntaxInterfaceCache
- (encodeCache
- (putModuleSyntaxInterfaceCache interface)))
- assertEqual
- "asserted ID is deterministic"
- (Right (moduleSyntaxAssertedId interface))
- (moduleSyntaxAssertedId
- <$> moduleSyntaxInterface [] delta)
- assertBool
- "normalized fixity changes syntax identity"
- (moduleSyntaxAssertedId interface
- /= moduleSyntaxAssertedId changedInterface)
- case moduleSyntaxInterface
- [ moduleSyntaxAssertedId interface
- , moduleSyntaxAssertedId interface
- ]
- delta of
- Left (DuplicateDirectSyntaxInterface duplicate) ->
- assertEqual
- "duplicate direct interface"
- (moduleSyntaxAssertedId interface)
- duplicate
- Left err ->
- assertFailure
- ("expected duplicate direct syntax input, got "
- <> show err)
- Right _ ->
- assertFailure
- "accepted a duplicate direct syntax input"
-
-expectRight :: Show err => Either err value -> IO value
-expectRight = \case
- Left err ->
- assertFailure (show err)
- >> fail "unreachable"
- Right value ->
- pure value
-
-expectedBaseRows :: [[(Marker, Associativity)]]
-expectedBaseRows =
- [ []
- , [ ("add", LeftAssoc)
- , ("union", LeftAssoc)
- , ("minus", LeftAssoc)
- , ("rminus", LeftAssoc)
- , ("monus", LeftAssoc)
- ]
- , [("relcomp", LeftAssoc)]
- , [("circ", LeftAssoc)]
- , [ ("mul", LeftAssoc)
- , ("inter", LeftAssoc)
- , ("rmul", LeftAssoc)
- ]
- , [("setminus", LeftAssoc)]
- , [("times", RightAssoc)]
- , []
- , [ ("rfrac", NonAssoc)
- , ("exp", NonAssoc)
- , ("unions", NonAssoc)
- , ("cumul", NonAssoc)
- , ("fst", NonAssoc)
- , ("snd", NonAssoc)
- , ("pow", NonAssoc)
- , ("neg", NonAssoc)
- , ("inv", NonAssoc)
- , ("abs", NonAssoc)
- , ("cons", NonAssoc)
- , ("pair", NonAssoc)
- , ("upair", NonAssoc)
- ]
- , [ ("emptyset", NonAssoc)
- , ("naturals", NonAssoc)
- , ("naturalsPlus", NonAssoc)
- , ("integers", NonAssoc)
- , ("rationals", NonAssoc)
- , ("reals", NonAssoc)
- , ("unit", NonAssoc)
- , ("zero", NonAssoc)
- ]
- ]
diff --git a/source/Test/Unit/Materialization.hs b/source/Test/Unit/Materialization.hs
deleted file mode 100644
index fcad7b5..0000000
--- a/source/Test/Unit/Materialization.hs
+++ /dev/null
@@ -1,357 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module Test.Unit.Materialization (unitTests) where
-
-import Base
-import Checking.Authority qualified as Authority
-import Checking.Core qualified as Core
-import Checking.Foundation qualified as Foundation
-import Checking.Identity qualified as Identity
-import Checking.Materialization qualified as Materialization
-import Checking.Semantic qualified as Semantic
-import Felix.Math.Codec
-import Felix.Module
-import Felix.Source
-
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "Validation applicability"
- [ testCase "keeps serializable candidate validation inert"
- keepsCandidateValidationInert
- , testCase "rejects inexact candidate validation"
- rejectsInexactCandidateValidation
- , testCase "rejects mismatched candidate fields"
- rejectsMismatchedCandidateFields
- , testCase "selects ordered declaration certificates"
- selectsDeclarationCertificate
- , testCase "keeps raw interface membership inert"
- keepsImportedMembershipInert
- ]
-
-keepsCandidateValidationInert :: Assertion
-keepsCandidateValidationInert = do
- fixture <- makeFixture
- let check =
- Materialization.checkCandidateValidation
- (fixtureTheory fixture)
- (fixturePrefix fixture)
- (fixtureProposition fixture)
- (fixtureAuthority fixture)
- (fixtureDirect fixture)
- (fixtureProofValidation fixture)
- assertEqual
- "freely constructed records yield only inert applicability"
- (Right ())
- check
- assertEqual
- "inert applicability data is reusable"
- (Right ())
- check
-
-rejectsInexactCandidateValidation :: Assertion
-rejectsInexactCandidateValidation = do
- fixture <- makeFixture
- let wrongKey =
- Semantic.proofValidationKey
- (Identity.theoremId
- (fixtureReference fixture))
- (Semantic.proofSyntaxId "other-proof")
- (fixturePrefix fixture)
- wrongValidation =
- Materialization.candidateProofValidation
- (Semantic.proofValidationRecord
- wrongKey
- (fixtureCertificate fixture))
- (Semantic.proofSyntaxId "proof")
- case Materialization.checkCandidateValidation
- (fixtureTheory fixture)
- (fixturePrefix fixture)
- (fixtureProposition fixture)
- (fixtureAuthority fixture)
- (fixtureDirect fixture)
- wrongValidation of
- Left Materialization.ProofValidationKeyMismatch{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected validation-key error: " <> show other)
- Right _ ->
- assertFailure "inexact proof validation key succeeded"
-
-rejectsMismatchedCandidateFields :: Assertion
-rejectsMismatchedCandidateFields = do
- fixture <- makeFixture
- let sourceAuthority =
- Authority.factAuthority
- (fixtureReference fixture)
- (Authority.authoritySafety
- (Authority.singletonEscapeKind
- Authority.SourceAxiom))
- sourceCertificate <- expectRight
- (Authority.validationCertificate
- sourceAuthority
- Authority.SourceAxiomAuthorization)
- let key =
- Semantic.proofValidationKey
- (Identity.theoremId (fixtureReference fixture))
- (Semantic.proofSyntaxId "proof")
- (fixturePrefix fixture)
- sourceValidation =
- Materialization.candidateProofValidation
- (Semantic.proofValidationRecord
- key
- sourceCertificate)
- (Semantic.proofSyntaxId "proof")
- case Materialization.checkCandidateValidation
- (fixtureTheory fixture)
- (fixturePrefix fixture)
- (fixtureProposition fixture)
- (fixtureAuthority fixture)
- (fixtureDirect fixture)
- sourceValidation of
- Left Materialization.CandidateCertificateTargetMismatch{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected target mismatch: " <> show other)
- Right _ ->
- assertFailure "mismatched safety was accepted"
- differentDirect <- expectRight
- (Authority.validationCertificate
- (fixtureAuthority fixture)
- (Authority.CheckedSourceProof
- [Authority.preparedRequestId
- Authority.PreparedRequestFof
- Authority.PreparedRequestDirect
- "different-request"]))
- let directValidation =
- Materialization.candidateProofValidation
- (Semantic.proofValidationRecord
- key
- differentDirect)
- (Semantic.proofSyntaxId "proof")
- case Materialization.checkCandidateValidation
- (fixtureTheory fixture)
- (fixturePrefix fixture)
- (fixtureProposition fixture)
- (fixtureAuthority fixture)
- (fixtureDirect fixture)
- directValidation of
- Left Materialization.CandidateDirectAuthorizationMismatch{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected direct-authorization mismatch: "
- <> show other)
- Right _ ->
- assertFailure "mismatched request list was accepted"
- closure <- expectRight
- (Identity.validateObjectClosure
- (fixtureTheory fixture)
- [])
- otherProposition <- expectRight
- (Identity.validatePropositionContent
- closure
- (Core.CImp Core.CFalsum Core.CFalsum))
- case Materialization.checkCandidateValidation
- (fixtureTheory fixture)
- (fixturePrefix fixture)
- otherProposition
- (fixtureAuthority fixture)
- (fixtureDirect fixture)
- (fixtureProofValidation fixture) of
- Left Materialization.CandidatePropositionMismatch{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected proposition mismatch: " <> show other)
- Right _ ->
- assertFailure "mismatched proposition content was accepted"
-
-selectsDeclarationCertificate :: Assertion
-selectsDeclarationCertificate = do
- fixture <- makeFixture
- let sourceAuthority =
- Authority.factAuthority
- (fixtureReference fixture)
- (Authority.authoritySafety
- (Authority.singletonEscapeKind
- Authority.SourceAxiom))
- sourceCertificate <- expectRight
- (Authority.validationCertificate
- sourceAuthority
- Authority.SourceAxiomAuthorization)
- let syntax =
- Semantic.declarationSyntaxId "declaration"
- producedTheorems =
- [ Identity.theoremId
- (fixtureReference fixture)
- , Identity.theoremId
- (fixtureReference fixture)
- ]
- key =
- Semantic.declarationValidationKey
- syntax
- (fixturePrefix fixture)
- []
- producedTheorems
- validation =
- Materialization.candidateDeclarationValidation
- (Semantic.declarationValidationRecord
- key
- [sourceCertificate, fixtureCertificate fixture])
- syntax []
- producedTheorems
- 1
- assertEqual
- "candidate ordinal selects the second certificate"
- (Right ())
- (Materialization.checkCandidateValidation
- (fixtureTheory fixture)
- (fixturePrefix fixture)
- (fixtureProposition fixture)
- (fixtureAuthority fixture)
- (fixtureDirect fixture)
- validation)
-
-keepsImportedMembershipInert :: Assertion
-keepsImportedMembershipInert = do
- fixture <- makeFixture
- occurrence <- expectRight
- (Materialization.checkImportedMembership
- (fixtureTheory fixture)
- (fixtureInterface fixture)
- (fixtureFingerprint fixture)
- (fixtureProposition fixture)
- (fixtureAuthority fixture))
- assertEqual
- "raw interface yields only its inert occurrence"
- (fixtureAuthority fixture)
- (Semantic.semanticFactAuthority occurrence)
- let wrongAuthority =
- Authority.factAuthority
- (fixtureReference fixture)
- (Authority.authoritySafety
- (Authority.singletonEscapeKind
- Authority.Omitted))
- case Materialization.checkImportedMembership
- (fixtureTheory fixture)
- (fixtureInterface fixture)
- (fixtureFingerprint fixture)
- (fixtureProposition fixture)
- wrongAuthority of
- Left Materialization.ImportedAuthorityMismatch{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected imported-authority error: " <> show other)
- Right _ ->
- assertFailure "imported authority mismatch succeeded"
-
-
-data Fixture = Fixture
- { fixtureTheory :: !Identity.TheoryId
- , fixtureReference :: !Identity.TheoremRef
- , fixtureProposition :: !Identity.CheckedPropositionContent
- , fixtureAuthority :: !Authority.FactAuthority
- , fixtureDirect :: !Authority.DirectAuthorization
- , fixtureCertificate :: !Authority.ValidationCertificate
- , fixtureFingerprint
- :: !Semantic.SemanticFactOccurrenceFingerprint
- , fixtureInterface :: !Semantic.SemanticInterface
- , fixturePrefix :: !Semantic.PrefixContextId
- , fixtureProofValidation
- :: !Materialization.CandidateValidation
- }
-
-makeFixture :: IO Fixture
-makeFixture = do
- foundation <- expectRight Foundation.checkedFoundation
- namespaceDigest <- expectRight
- (hashCanonicalFields
- "materialization-test-namespace"
- ["root"])
- relative <- expectRight (safeRelativePath "producer.tex")
- let theory =
- Identity.theoryId foundation
- owner =
- moduleNameFromParts
- (sourceNamespaceIdFromDigest namespaceDigest)
- relative
- closure <- expectRight
- (Identity.validateObjectClosure theory [])
- proposition <- expectRight
- (Identity.validatePropositionContent
- closure Core.CFalsum)
- let reference =
- Identity.theoremRef
- theory
- (Identity.checkedPropositionId proposition)
- authority =
- Authority.factAuthority
- reference
- Authority.cleanAuthoritySafety
- direct =
- Authority.CheckedSourceProof []
- slot =
- Semantic.factSlot owner (localFactOrdinal 0)
- fingerprint =
- Semantic.semanticFactOccurrenceFingerprint
- slot authority
- occurrence =
- Semantic.semanticFactOccurrence
- slot
- authority
- Semantic.SearchEligible
- declaration =
- Semantic.declarationSlot
- owner
- (localDeclarationOrdinal 0)
- certificate <- expectRight
- (Authority.validationCertificate authority direct)
- delta <- expectRight
- (Semantic.declarationInterfaceDelta
- declaration
- [occurrence]
- []
- []
- [Identity.checkedPropositionId proposition]
- Semantic.emptySemanticEnvironmentDelta)
- interface <- expectRight
- (Semantic.semanticInterface owner [] [delta])
- prefix <- expectRight
- (Semantic.initialPrefixContextId theory owner [])
- let syntax =
- Semantic.proofSyntaxId "proof"
- key =
- Semantic.proofValidationKey
- (Identity.theoremId reference)
- syntax prefix
- pure
- Fixture
- { fixtureTheory = theory
- , fixtureReference = reference
- , fixtureProposition = proposition
- , fixtureAuthority = authority
- , fixtureDirect = direct
- , fixtureCertificate = certificate
- , fixtureFingerprint = fingerprint
- , fixtureInterface = interface
- , fixturePrefix = prefix
- , fixtureProofValidation =
- Materialization.candidateProofValidation
- (Semantic.proofValidationRecord
- key certificate)
- syntax
- }
-
-expectRight :: Show error => Either error value -> IO value
-expectRight = \case
- Left err ->
- assertFailure (show err) >> fail "unreachable"
- Right value ->
- pure value
diff --git a/source/Test/Unit/Meaning.hs b/source/Test/Unit/Meaning.hs
deleted file mode 100644
index acb33d0..0000000
--- a/source/Test/Unit/Meaning.hs
+++ /dev/null
@@ -1,1119 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Unit.Meaning (unitTests) where
-
-import Base
-import Felix.Meaning
-import Report.Location
-import Syntax.Abstract qualified as Raw
-import Syntax.Internal qualified as Sem
-import Syntax.LexicalPhrase
- ( unsafeReadPhrase
- , unsafeReadPhraseSgPl
- )
-
-import Bound (instantiate)
-import Control.Monad.Except (runExceptT)
-import Control.Monad.State (evalState, gets)
-import Data.Map qualified as Map
-import Data.Set qualified as Set
-import Test.Tasty
-import Test.Tasty.HUnit
-
-unitTests :: TestTree
-unitTests =
- testGroup "Meaning"
- [ testCase "relation applications reject missing and extra parameters" do
- for_ [(0, Raw.ParameterArity 0), (2, Raw.ParameterArity 2)]
- \(actualCount, actualArity) ->
- case meaning [relationClaim actualCount] of
- Left
- (GlossRelationApplicationError
- (Sem.RelationParameterArityMismatch
- actualLocation
- actualSymbol
- expectedArity
- reportedActualArity)) -> do
- assertEqual
- "relation location"
- relationLocation
- actualLocation
- assertEqual
- "relation symbol"
- relationSymbol
- actualSymbol
- assertEqual
- "expected parameter arity"
- (Raw.ParameterArity 1)
- expectedArity
- assertEqual
- "actual parameter arity"
- actualArity
- reportedActualArity
- Left err ->
- assertFailure
- ("expected a relation arity error, got "
- <> show err)
- Right _ ->
- assertFailure
- "expected relation arity validation to fail"
- , testCase
- "dependent replacement domains report their occurrences"
- dependentReplacementDomains
- , testCase
- "replacement domains remain outside own and future binders"
- independentReplacementDomains
- , testCase
- "functional definitions reject quantified terms with source context"
- quantifiedFunctionalDefinition
- , testCase
- "unsupported source constructs return located errors"
- unsupportedSourceConstructs
- , testCase
- "proof-local function definitions reject mismatched heads"
- proofLocalFunctionDefinitionMismatches
- , testCase
- "abbreviations reject duplicate parameters with source context"
- duplicateAbbreviationParameters
- , testCase
- "abbreviations reject named free body variables"
- freeAbbreviationBodyVariable
- , testCase
- "abbreviation parameters retain positional slots"
- orderedAbbreviationParameters
- , testCase
- "quantified noun binders resolve their whole scope"
- quantifiedNounBinderScope
- , testCase
- "quantified noun binders obey lexical scope"
- quantifiedNounLexicalScope
- , testCase
- "resolved binder adaptation is injective and ignores trivia"
- resolvedBinderAdapter
- ]
-
-dependentReplacementDomains :: Assertion
-dependentReplacementDomains =
- for_ cases \(label, replacement, expectedLocation) ->
- assertEqual
- label
- (Left
- (DependentReplacementDomainNotSupported
- expectedLocation))
- (glossTestExpr replacement)
- where
- cases =
- [ ( "two-domain replacement"
- , replacementExpr
- (Raw.ExprVar y)
- ( (x, rawInteger 1)
- :| [(y, rawVarAt twoXLocation "x")]
- )
- , twoXLocation
- )
- , ( "three-domain replacement reports its first dependent occurrence"
- , replacementExpr
- (Raw.ExprVar z)
- ( (x, rawInteger 1)
- :| [ (y, rawInteger 2)
- , (z, Raw.ExprOp
- Nowhere
- (testFunctionSymbol "dependent_domain" 2)
- [ rawVarAt threeYLocation "y"
- , rawVarAt threeXLocation "x"
- ])
- ]
- )
- , threeYLocation
- )
- ]
- x = Raw.NamedVar "x"
- y = Raw.NamedVar "y"
- z = Raw.NamedVar "z"
- twoXLocation = mkLocation replacementFile 3 17
- threeYLocation = mkLocation replacementFile 4 29
- threeXLocation = mkLocation replacementFile 4 32
-
-independentReplacementDomains :: Assertion
-independentReplacementDomains =
- case glossTestExpr replacement of
- Right
- (Sem.ReplaceFun
- ( (actualX, Sem.TermVar actualOwnX)
- :| [ (actualY, Sem.TermVar actualFutureZ)
- , ( actualZ
- , Sem.TermSymbol
- _thirdDomainLocation
- (Sem.SymbolInteger 3)
- []
- )
- ]
- )
- valueScope
- conditionScope) -> do
- assertEqual
- "replacement binder order"
- [x, y, z]
- [actualX, actualY, actualZ]
- assertEqual
- "own-domain occurrence remains free"
- ownXLocation
- (locate actualOwnX)
- assertEqual
- "future-binder occurrence remains free"
- futureZLocation
- (locate actualFutureZ)
- assertEqual
- "replacement value lowering"
- expectedValue
- (instantiate instantiateBinder valueScope)
- assertEqual
- "default replacement condition"
- Sem.Top
- (instantiate instantiateBinder conditionScope)
- Right expr ->
- assertFailure
- ("expected an independent functional replacement, got "
- <> show expr)
- Left err ->
- assertFailure
- ("expected independent replacement domains to succeed, got "
- <> show err)
- where
- replacement =
- replacementExpr
- ( Raw.ExprOp
- replacementValueLocation
- replacementValueSymbol
- [ rawVarAt replacementValueLocation "x"
- , rawVarAt replacementValueLocation "y"
- , rawVarAt replacementValueLocation "z"
- ]
- )
- ( (x, rawVarAt ownXLocation "x")
- :| [ (y, rawVarAt futureZLocation "z")
- , (z, rawInteger 3)
- ]
- )
- x = Raw.NamedVar "x"
- y = Raw.NamedVar "y"
- z = Raw.NamedVar "z"
- ownXLocation = mkLocation replacementFile 6 7
- futureZLocation = mkLocation replacementFile 6 16
- replacementValueLocation = mkLocation replacementFile 6 29
- replacementValueSymbol = testFunctionSymbol "replacement_value" 3
- expectedValue =
- Sem.TermSymbol
- replacementValueLocation
- (Sem.SymbolMixfix replacementValueSymbol)
- [ closedInteger 11
- , closedInteger 22
- , closedInteger 33
- ]
- instantiateBinder binder
- | binder == x = closedInteger 11
- | binder == y = closedInteger 22
- | binder == z = closedInteger 33
- | otherwise = closedInteger (-1)
-
-replacementExpr
- :: Raw.Expr
- -> NonEmpty (Raw.VarSymbol, Raw.Expr)
- -> Raw.Expr
-replacementExpr value bounds =
- Raw.ExprReplace replacementLocation value bounds Nothing
-
-rawVarAt :: Location -> Text -> Raw.Expr
-rawVarAt location name =
- Raw.ExprVar (Raw.NamedVarAt location name)
-
-rawInteger :: Int -> Raw.Expr
-rawInteger =
- Raw.ExprInteger Nowhere
-
-glossTestExpr :: Raw.Expr -> Either GlossError Sem.Expr
-glossTestExpr expr =
- evalState
- (runExceptT (glossExpr expr))
- initialGlossState
-
-glossTestStmt :: Raw.Stmt -> Either GlossError Sem.Formula
-glossTestStmt statement =
- evalState
- (runExceptT (glossStmt statement))
- initialGlossState
-
-unsupportedSourceConstructs :: Assertion
-unsupportedSourceConstructs = do
- assertEqual
- "definite-description term"
- (Left (IotaTermNotSupported iotaLocation))
- (runGlossUnit (glossH0Term [] iotaTerm))
- assertEqual
- "definite-function assumption"
- (Left
- (DefiniteFunctionAssumptionNotSupported
- definiteFunctionLocation))
- (runGlossUnit (glossAsm definiteFunctionAssumption))
- where
- iotaTerm =
- Raw.TermIota
- iotaLocation
- (Raw.NamedVarAt iotaLocation "x")
- (Raw.StmtFormula
- (Raw.PropositionalConstant iotaLocation Raw.IsTop))
- definiteFunctionAssumption =
- Raw.AsmLetThe
- (Raw.NamedVarAt definiteFunctionLocation "f")
- (Raw.Fun
- definiteFunctionLocation
- (Raw.mkLexicalItemSgPl
- (unsafeReadPhraseSgPl "function[/s]")
- "function")
- [])
-
-runGlossUnit :: Gloss a -> Either GlossError ()
-runGlossUnit action =
- void
- (evalState
- (runExceptT action)
- initialGlossState)
-
-quantifiedNounBinderScope :: Assertion
-quantifiedNounBinderScope = do
- case glossTestStmt (namedSetEquality "x") of
- Right formula@(Sem.Quantified Sem.Universally scope) -> do
- assertEqual
- "the written binder does not remain free"
- Set.empty
- (Sem.freeVars formula)
- assertEqual
- "the continuation uses the quantified witness"
- (Sem.Top
- `Sem.Implies`
- Sem.Equals
- equalityLocation
- witness
- witness)
- (instantiate (const witness) scope)
- Right formula ->
- assertFailure
- ("expected a universal named binder, got " <> show formula)
- Left err ->
- assertFailure
- ("expected the named binder to gloss, got " <> show err)
-
- case glossTestStmt constrainedNamedBinder of
- Right formula@(Sem.Quantified Sem.Universally scope) -> do
- assertEqual
- "only the ambient noun argument remains free"
- (Set.singleton ambientVariable)
- (Sem.freeVars formula)
- assertEqual
- "noun, modifier, such-that, and continuation share the binder"
- expectedConstrainedBody
- (instantiate (const witness) scope)
- Right formula ->
- assertFailure
- ("expected a constrained universal binder, got "
- <> show formula)
- Left err ->
- assertFailure
- ("expected the constrained binder to gloss, got "
- <> show err)
- where
- witness = closedInteger 17
- ambientVariable =
- Raw.NamedVarAt ambientLocation "T"
- nounConstraint =
- Sem.FormulaNoun
- nounLocation
- witness
- subsetNounPattern
- [Sem.TermVar ambientVariable]
- modifierConstraint =
- Sem.FormulaAdj
- modifierLocation
- witness
- modifierPattern
- [witness]
- suchThatConstraint =
- Sem.Equals suchThatLocation witness witness
- continuation =
- Sem.Equals equalityLocation witness witness
- expectedConstrainedBody =
- Sem.makeConjunction
- [ suchThatConstraint
- , Sem.makeConjunction
- [nounConstraint, modifierConstraint]
- ]
- `Sem.Implies` continuation
-
-quantifiedNounLexicalScope :: Assertion
-quantifiedNounLexicalScope = do
- assertEqual
- "alpha-renaming a referenced binder"
- (glossTestStmt (namedSetEquality "x"))
- (glossTestStmt (namedSetEquality "renamed"))
- assertEqual
- "a vacuous written name is semantic trivia"
- (glossTestStmt (vacuousSetStatement Nothing))
- (glossTestStmt
- (vacuousSetStatement
- (Just
- (Raw.NamedVarAt binderLocation "unused"))))
-
- assertEqual
- "overlapping sibling names are rejected"
- (Left
- (DuplicateQuantifiedNounBinder
- firstSiblingLocation
- secondSiblingLocation
- "same"))
- (glossTestStmt duplicateSiblingStatement)
-
- case glossTestStmt nestedShadowingStatement of
- Right (Sem.Quantified Sem.Universally outerScope) ->
- case instantiate (const outerWitness) outerScope of
- Sem.Top
- `Sem.Implies`
- Sem.Quantified Sem.Existentially innerScope ->
- assertEqual
- "the nearest binder owns the nested occurrences"
- expectedInnerBody
- (instantiate
- (const innerWitness)
- innerScope)
- body ->
- assertFailure
- ("expected a nested existential binder, got "
- <> show body)
- Right formula ->
- assertFailure
- ("expected an outer universal binder, got " <> show formula)
- Left err ->
- assertFailure
- ("expected nested shadowing to gloss, got " <> show err)
- where
- outerWitness = closedInteger 23
- innerWitness = closedInteger 29
- expectedInnerBody =
- Sem.makeConjunction
- [ Sem.Equals
- nestedSuchThatLocation
- innerWitness
- innerWitness
- , Sem.Top
- ]
- `Sem.And`
- Sem.Equals
- nestedEqualityLocation
- outerWitness
- innerWitness
-
-resolvedBinderAdapter :: Assertion
-resolvedBinderAdapter = do
- case ( binderAdapterObservation
- ("first", firstAdapterLocation)
- ("second", secondAdapterLocation)
- , binderAdapterObservation
- ("alpha", alternateFirstLocation)
- ("beta", alternateSecondLocation)
- ) of
- ( Right (firstId :| [secondId], firstTokens, firstResult)
- , Right (alternateIds, alternateTokens, alternateResult)
- ) -> do
- assertBool
- "pre-adapter local identities are distinct"
- (firstId /= secondId)
- case
- ( Map.lookup firstId firstTokens
- , Map.lookup secondId firstTokens
- ) of
- (Just firstToken, Just secondToken) -> do
- assertBool
- "legacy tokens are injective"
- (firstToken /= secondToken)
- assertBool
- "legacy tokens avoid ambient variables"
- ( firstToken /= adapterAmbientVariable
- && secondToken
- /= adapterAmbientVariable
- )
- tokens ->
- assertFailure
- ("expected two adapter assignments, got "
- <> show tokens)
- assertEqual
- "trivia does not affect local identities"
- (firstId :| [secondId])
- alternateIds
- assertEqual
- "trivia does not affect adapter assignments"
- firstTokens
- alternateTokens
- assertEqual
- "trivia does not affect the alpha-normal result"
- firstResult
- alternateResult
- assertEqual
- "ambient references pass through unchanged"
- (Set.singleton adapterAmbientVariable)
- (Sem.freeVars firstResult)
- (firstResult, secondResult) ->
- assertFailure
- ("expected successful adapter observations, got "
- <> show (firstResult, secondResult))
-
- assertEqual
- "an unadapted local reference is a located typed error"
- (Left
- (GlossResolvedBinderAdapterError
- firstAdapterLocation
- (UnknownResolvedLocal (LocalId 0))))
- ( evalState
- (runExceptT
- do
- binder <-
- freshH0Binder
- firstAdapterLocation
- (Just
- (Raw.NamedVarAt
- firstAdapterLocation
- "unadapted"))
- lowerH0Expr
- (Sem.TermVar
- (LocalRef (h0BinderId binder))))
- initialGlossState
- )
-
-binderAdapterObservation
- :: (Text, Location)
- -> (Text, Location)
- -> Either
- GlossError
- ( NonEmpty LocalId
- , Map LocalId Sem.VarSymbol
- , Sem.Expr
- )
-binderAdapterObservation
- (firstName, firstLocation)
- (secondName, secondLocation) =
- evalState
- (runExceptT do
- firstBinder <-
- freshH0Binder
- firstLocation
- (Just
- (Raw.NamedVarAt firstLocation firstName))
- secondBinder <-
- freshH0Binder
- secondLocation
- (Just
- (Raw.NamedVarAt secondLocation secondName))
- let firstId = h0BinderId firstBinder
- secondId = h0BinderId secondBinder
- resolvedBody =
- Sem.TermSymbol
- Nowhere
- (Sem.SymbolMixfix adapterBodySymbol)
- [ Sem.TermVar (LocalRef firstId)
- , Sem.TermVar (LocalRef secondId)
- , Sem.TermVar
- (AmbientRef adapterAmbientVariable)
- ]
- quantifiedTerms =
- [ H0QuantifiedTerm
- Raw.Universally
- firstBinder
- []
- , H0QuantifiedTerm
- Raw.Existentially
- secondBinder
- []
- ]
- adapted <-
- applyH0Quantifiers quantifiedTerms resolvedBody
- >>= lowerH0Expr
- assignments <- gets legacyLocalTokens
- pure
- ( firstId :| [secondId]
- , assignments
- , adapted
- ))
- initialGlossState
-
-namedSetEquality :: Text -> Raw.Stmt
-namedSetEquality name =
- Raw.StmtVerbPhrase
- ( quantifiedSetTerm
- Raw.Universally
- binderLocation
- (Just
- (Raw.NamedVarAt binderLocation name))
- []
- Nothing
- :| []
- )
- (equalityVerbPhrase
- equalityLocation
- (rawTermVar equalityLocation name))
-
-constrainedNamedBinder :: Raw.Stmt
-constrainedNamedBinder =
- Raw.StmtVerbPhrase
- ( Raw.TermQuantified
- Raw.Universally
- binderLocation
- ( Raw.NounPhrase
- [ Raw.AdjL
- modifierLocation
- modifierPattern
- [rawTermVar modifierLocation "x"]
- ]
- ( Raw.Noun
- nounLocation
- subsetNounPattern
- [rawTermVar ambientLocation "T"]
- )
- (Just
- (Raw.NamedVarAt binderLocation "x"))
- []
- (Just
- (equalityStatement
- suchThatLocation
- "x"
- "x"))
- )
- :| []
- )
- (equalityVerbPhrase
- equalityLocation
- (rawTermVar equalityLocation "x"))
-
-vacuousSetStatement :: Maybe Raw.VarSymbol -> Raw.Stmt
-vacuousSetStatement mayName =
- Raw.StmtVerbPhrase
- ( quantifiedSetTerm
- Raw.Universally
- binderLocation
- mayName
- []
- Nothing
- :| []
- )
- ( Raw.VPAdj
- ( Raw.Adj
- reflexiveLocation
- reflexivePattern
- []
- :| []
- )
- )
-
-duplicateSiblingStatement :: Raw.Stmt
-duplicateSiblingStatement =
- Raw.StmtVerbPhrase
- ( quantifiedSetTerm
- Raw.Universally
- firstSiblingLocation
- (Just
- (Raw.NamedVarAt firstSiblingLocation "same"))
- []
- Nothing
- :| [ quantifiedSetTerm
- Raw.Existentially
- secondSiblingLocation
- (Just
- (Raw.NamedVarAt secondSiblingLocation "same"))
- []
- Nothing
- ]
- )
- ( Raw.VPAdj
- ( Raw.Adj
- reflexiveLocation
- reflexivePattern
- []
- :| []
- )
- )
-
-nestedShadowingStatement :: Raw.Stmt
-nestedShadowingStatement =
- Raw.StmtVerbPhrase
- ( quantifiedSetTerm
- Raw.Universally
- outerBinderLocation
- (Just
- (Raw.NamedVarAt outerBinderLocation "shadow"))
- []
- Nothing
- :| []
- )
- ( equalityVerbPhrase
- nestedEqualityLocation
- ( Raw.TermQuantified
- Raw.Existentially
- innerBinderLocation
- ( Raw.NounPhrase
- []
- (setNoun innerBinderLocation)
- (Just
- (Raw.NamedVarAt
- innerBinderLocation
- "shadow"))
- []
- (Just
- (equalityStatement
- nestedSuchThatLocation
- "shadow"
- "shadow"))
- )
- )
- )
-
-quantifiedSetTerm
- :: Raw.Quantifier
- -> Location
- -> Maybe Raw.VarSymbol
- -> [Raw.AdjL]
- -> Maybe Raw.Stmt
- -> Raw.Term
-quantifiedSetTerm quantifier location mayName leftAdjectives maySuchThat =
- Raw.TermQuantified
- quantifier
- location
- ( Raw.NounPhrase
- leftAdjectives
- (setNoun location)
- mayName
- []
- maySuchThat
- )
-
-setNoun :: Location -> Raw.Noun
-setNoun location =
- Raw.Noun location setNounPattern []
-
-rawTermVar :: Location -> Text -> Raw.Term
-rawTermVar location name =
- Raw.TermExpr (rawVarAt location name)
-
-equalityStatement :: Location -> Text -> Text -> Raw.Stmt
-equalityStatement location leftName rightName =
- Raw.StmtVerbPhrase
- (rawTermVar location leftName :| [])
- (equalityVerbPhrase
- location
- (rawTermVar location rightName))
-
-equalityVerbPhrase :: Location -> Raw.Term -> Raw.VerbPhrase
-equalityVerbPhrase location argument =
- Raw.VPAdj
- ( Raw.Adj
- location
- equalityPattern
- [argument]
- :| []
- )
-
-setNounPattern :: Raw.LexicalItemSgPl
-setNounPattern =
- Raw.mkLexicalItemSgPl
- (unsafeReadPhraseSgPl "set[/s]")
- "set"
-
-subsetNounPattern :: Raw.LexicalItemSgPl
-subsetNounPattern =
- Raw.mkLexicalItemSgPl
- (unsafeReadPhraseSgPl "subset[/s] of ?")
- "test_subset"
-
-modifierPattern :: Raw.LexicalItem
-modifierPattern =
- Raw.mkLexicalItem
- (unsafeReadPhrase "related to ?")
- "test_modifier"
-
-equalityPattern :: Raw.LexicalItem
-equalityPattern =
- Raw.mkLexicalItem
- (unsafeReadPhrase "equal to ?")
- "eq"
-
-reflexivePattern :: Raw.LexicalItem
-reflexivePattern =
- Raw.mkLexicalItem
- (unsafeReadPhrase "reflexive")
- "test_reflexive"
-
-adapterBodySymbol :: Raw.FunctionSymbol
-adapterBodySymbol =
- testFunctionSymbol "adapter_body" 3
-
-adapterAmbientVariable :: Sem.VarSymbol
-adapterAmbientVariable =
- Sem.FreshVar 0
-
-binderLocation, equalityLocation, nounLocation, ambientLocation :: Location
-binderLocation = mkLocation (FileId 48) 2 7
-equalityLocation = mkLocation (FileId 48) 2 24
-nounLocation = mkLocation (FileId 48) 3 7
-ambientLocation = mkLocation (FileId 48) 3 20
-
-modifierLocation, suchThatLocation, reflexiveLocation :: Location
-modifierLocation = mkLocation (FileId 48) 3 27
-suchThatLocation = mkLocation (FileId 48) 3 42
-reflexiveLocation = mkLocation (FileId 48) 4 17
-
-firstSiblingLocation, secondSiblingLocation :: Location
-firstSiblingLocation = mkLocation (FileId 48) 5 7
-secondSiblingLocation = mkLocation (FileId 48) 5 24
-
-outerBinderLocation, innerBinderLocation :: Location
-outerBinderLocation = mkLocation (FileId 48) 6 7
-innerBinderLocation = mkLocation (FileId 48) 6 31
-
-nestedSuchThatLocation, nestedEqualityLocation :: Location
-nestedSuchThatLocation = mkLocation (FileId 48) 6 45
-nestedEqualityLocation = mkLocation (FileId 48) 6 20
-
-firstAdapterLocation, secondAdapterLocation :: Location
-firstAdapterLocation = mkLocation (FileId 48) 7 7
-secondAdapterLocation = mkLocation (FileId 48) 7 19
-
-alternateFirstLocation, alternateSecondLocation :: Location
-alternateFirstLocation = mkLocation (FileId 48) 8 7
-alternateSecondLocation = mkLocation (FileId 48) 8 19
-
-replacementFile :: FileId
-replacementFile = FileId 47
-
-replacementLocation :: Location
-replacementLocation = mkLocation replacementFile 2 1
-
-iotaLocation :: Location
-iotaLocation = mkLocation (FileId 49) 3 5
-
-definiteFunctionLocation :: Location
-definiteFunctionLocation = mkLocation (FileId 49) 4 9
-
-proofLocalFunctionDefinitionMismatches :: Assertion
-proofLocalFunctionDefinitionMismatches =
- for_ mismatchCases \(label, proof, expectedError) ->
- assertEqual
- label
- (Left expectedError)
- (meaning
- [ Raw.BlockProof
- proofLocation
- proof
- proofLocation
- ])
- where
- mismatchCases =
- [ ( "argument and domain binder"
- , Raw.DefineFunction
- proofLocation
- "f"
- "x"
- (Raw.ExprVar "x")
- "y"
- (Raw.ExprVar "domain")
- (Raw.Omitted proofLocation)
- , GlossProofFunctionArgumentMismatch
- proofLocation
- "x"
- "y"
- )
- , ( "declared and defined function name"
- , Raw.DefineFunctionLocal
- proofLocation
- "f"
- "domain"
- (Raw.ExprVar "range")
- "g"
- "x"
- ( ( Raw.ExprVar "x"
- , Raw.PropositionalConstant
- proofLocation
- Raw.IsTop
- )
- :| []
- )
- (Raw.Omitted proofLocation)
- , GlossProofFunctionNameMismatch
- proofLocation
- "f"
- "g"
- )
- ]
- proofLocation = mkLocation (FileId 46) 5 9
-
-quantifiedFunctionalDefinition :: Assertion
-quantifiedFunctionalDefinition =
- case meaning [definitionBlock] of
- Left
- (GlossDefnError
- actualLocation
- DefnErrorQuantifiedRhsTerm
- actualMarker) -> do
- assertEqual
- "quantified term location"
- termLocation
- actualLocation
- assertEqual
- "definition marker"
- definitionMarker
- actualMarker
- Left err ->
- assertFailure
- ("expected a quantified definition term error, got "
- <> show err)
- Right _ ->
- assertFailure
- "expected quantified definition term validation to fail"
- where
- definitionBlock =
- Raw.BlockDefn
- blockLocation
- Nothing
- definitionMarker
- ( Raw.DefnFun
- []
- ( Raw.Fun
- blockLocation
- ( Raw.mkLexicalItemSgPl
- (unsafeReadPhraseSgPl "value[/s] of ?")
- "quantified_function"
- )
- ["argument"]
- )
- Nothing
- ( Raw.TermQuantified
- Raw.Existentially
- termLocation
- ( Raw.NounPhrase
- []
- ( Raw.Noun
- termLocation
- ( Raw.mkLexicalItemSgPl
- (unsafeReadPhraseSgPl "set[/s]")
- "set"
- )
- []
- )
- Nothing
- []
- Nothing
- )
- )
- )
- definitionMarker = "quantified_definition"
- blockLocation = mkLocation (FileId 44) 8 1
- termLocation = mkLocation (FileId 44) 8 29
-
-duplicateAbbreviationParameters :: Assertion
-duplicateAbbreviationParameters = do
- let marker = "duplicate_abbreviation"
- duplicate = Raw.NamedVar "duplicate"
- expectAbbreviationError
- marker
- [duplicate, duplicate]
- (Raw.ExprVar duplicate)
- \case
- DuplicateAbbreviationParameters actualVariables ->
- assertEqual
- "duplicate parameter names"
- (duplicate :| [])
- actualVariables
- err ->
- assertFailure
- ("expected duplicate abbreviation parameters, got "
- <> show err)
-
-freeAbbreviationBodyVariable :: Assertion
-freeAbbreviationBodyVariable = do
- let marker = "free_abbreviation_body"
- freeVariable = Raw.NamedVar "free"
- expectAbbreviationError
- marker
- ["parameter"]
- (Raw.ExprVar freeVariable)
- \case
- FreeAbbreviationBodyVariables actualVariables ->
- assertEqual
- "free body variable names"
- (freeVariable :| [])
- actualVariables
- err ->
- assertFailure
- ("expected free abbreviation variables, got "
- <> show err)
-
-orderedAbbreviationParameters :: Assertion
-orderedAbbreviationParameters = do
- let first = Raw.NamedVar "first"
- second = Raw.NamedVar "second"
- third = Raw.NamedVar "third"
- firstArgument = closedInteger 11
- secondArgument = closedInteger 22
- thirdArgument = closedInteger 33
- arguments =
- [ firstArgument
- , secondArgument
- , thirdArgument
- ]
- expectedBody =
- Sem.TermSymbol
- abbreviationLocation
- (Sem.SymbolMixfix abbreviationBodySymbol)
- [thirdArgument, firstArgument, secondArgument]
- unexpectedArgument = closedInteger (-1)
- case meaning
- [ abbreviationBlock
- abbreviationLocation
- "ordered_abbreviation"
- [first, second, third]
- ( Raw.ExprOp
- abbreviationLocation
- abbreviationBodySymbol
- [ Raw.ExprVar third
- , Raw.ExprVar first
- , Raw.ExprVar second
- ]
- )
- ] of
- Right
- [Sem.BlockAbbr
- _actualLocation
- _actualMarker
- (Sem.Abbreviation _actualSymbol scope)] ->
- assertEqual
- "instantiated abbreviation body"
- expectedBody
- ( instantiate
- (\parameterIndex ->
- nth parameterIndex arguments
- ?? unexpectedArgument)
- scope
- )
- Right blocks ->
- assertFailure
- ("expected one glossed abbreviation, got "
- <> show blocks)
- Left err ->
- assertFailure
- ("expected a valid abbreviation, got "
- <> show err)
-
-expectAbbreviationError
- :: Raw.Marker
- -> [Raw.VarSymbol]
- -> Raw.Expr
- -> (AbbreviationParameterError -> Assertion)
- -> Assertion
-expectAbbreviationError marker parameters body checkError =
- case meaning
- [ abbreviationBlock
- abbreviationLocation
- marker
- parameters
- body
- ] of
- Left
- (GlossAbbreviationError
- actualLocation
- actualMarker
- abbreviationError) -> do
- assertEqual
- "abbreviation location"
- abbreviationLocation
- actualLocation
- assertEqual
- "abbreviation marker"
- marker
- actualMarker
- checkError abbreviationError
- Left err ->
- assertFailure
- ("expected an abbreviation parameter error, got "
- <> show err)
- Right _ ->
- assertFailure
- "expected abbreviation parameter validation to fail"
-
-abbreviationBlock
- :: Location
- -> Raw.Marker
- -> [Raw.VarSymbol]
- -> Raw.Expr
- -> Raw.Block
-abbreviationBlock location marker parameters body =
- Raw.BlockAbbr
- location
- Nothing
- marker
- ( Raw.AbbreviationEq
- ( Raw.SymbolPattern
- (testFunctionSymbol
- "abbreviation_head"
- (length parameters))
- parameters
- )
- body
- )
-
-abbreviationBodySymbol :: Raw.FunctionSymbol
-abbreviationBodySymbol =
- testFunctionSymbol "abbreviation_body" 3
-
-testFunctionSymbol :: Text -> Int -> Raw.FunctionSymbol
-testFunctionSymbol name arity =
- Raw.mkMixfixItem
- (Just (Raw.Command name) : replicate arity Nothing)
- (Raw.Marker name)
- Raw.NonAssoc
-
-closedInteger :: Int -> Sem.ExprOf a
-closedInteger value =
- Sem.TermSymbol
- Nowhere
- (Sem.SymbolInteger value)
- []
-
-abbreviationLocation :: Location
-abbreviationLocation =
- mkLocation (FileId 43) 8 12
-
-relationClaim :: Int -> Raw.Block
-relationClaim actualParameterCount =
- Raw.BlockClaim
- Raw.Proposition
- relationLocation
- Nothing
- "relation_arity"
- (Raw.Claim []
- (Raw.StmtFormula
- (Raw.FormulaChain
- (Raw.ChainBase
- (Raw.ExprVar "x" :| [])
- Raw.Positive
- (Raw.Relation
- relationLocation
- relationSymbol
- (replicate
- actualParameterCount
- (Raw.ExprVar "p")))
- (Raw.ExprVar "y" :| [])))))
-
-relationSymbol :: Raw.RelationSymbol
-relationSymbol =
- Raw.RelationSymbol
- (Raw.Command "parametric")
- (Raw.ParameterArity 1)
- "parametric"
-
-relationLocation :: Location
-relationLocation = mkLocation (FileId 42) 7 11
diff --git a/source/Test/Unit/Module.hs b/source/Test/Unit/Module.hs
deleted file mode 100644
index 13fe90d..0000000
--- a/source/Test/Unit/Module.hs
+++ /dev/null
@@ -1,9759 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module Test.Unit.Module (unitTests) where
-
-import Base
-import Checking.Authority qualified as Authority
-import Checking.Backend.Problem qualified as Backend
-import Checking.Core qualified as Core
-import Checking.Declaration qualified as Declaration
-import Checking.Exact qualified as Exact
-import Checking.Exact.Datatype qualified as ExactDatatype
-import Checking.Exact.Inductive qualified as ExactInductive
-import Checking.Exact.Proof qualified as ExactProof
-import Checking.FinalPrelude qualified as FinalPrelude
-import Checking.Foundation qualified as Foundation
-import Checking.Identity qualified as Identity
-import Checking.Module qualified as Module
-import Checking.Semantic qualified as Semantic
-import Checking.Typed.Inductive qualified as TypedInductive
-import Felix.CommandLine qualified as CommandLine
-import Felix.Module
-import Felix.Math.Codec
-import Felix.Parse qualified as Parse
-import Felix.Prelude qualified as Prelude
-import Felix.Source
-import Felix.Source.Content qualified as Content
-import Felix.Store qualified as Store
-import Felix.Verification qualified as Verification
-import Felix.Workspace qualified as Workspace
-import Report.Location
-import Felix.Provers qualified as Provers
-import Paths_felix qualified as Paths
-import Syntax.Abstract qualified as Raw
-import Syntax.Internal qualified as Internal
-import Syntax.Interface qualified as Syntax
-import Syntax.Lexicon qualified as Lexicon
-import Syntax.Pragma qualified as Pragma
-
-import Control.Concurrent (threadDelay)
-import Control.Concurrent.STM
- ( atomically
- , check
- , newEmptyTMVarIO
- , newTQueueIO
- , newTVarIO
- , putTMVar
- , readTQueue
- , readTVar
- , takeTMVar
- , tryReadTMVar
- , tryReadTQueue
- , writeTQueue
- , writeTVar
- )
-import Control.Exception (bracket)
-import Control.Exception qualified as Exception
-import Control.Monad (foldM, when)
-import Data.ByteString qualified as ByteString
-import Data.Text qualified as StrictText
-import Data.Text.Encoding qualified as Text
-import Data.IORef
- ( IORef
- , atomicModifyIORef'
- , modifyIORef'
- , newIORef
- , readIORef
- )
-import Data.List (sort)
-import Data.Map.Strict qualified as Map
-import Data.Set qualified as Set
-import Data.Vector qualified as Vector
-import Numeric.Natural (Natural)
-import System.Directory
- ( createDirectoryIfMissing
- , doesFileExist
- , getCurrentDirectory
- , getPermissions
- , setOwnerExecutable
- , setPermissions
- )
-import System.FilePath.Posix qualified as Posix
-import System.IO.Temp qualified as Temp
-import System.Timeout qualified as Timeout
-import Test.Tasty
-import Test.Tasty.HUnit
-import UnliftIO.Async (withAsync, wait)
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "Typed module inputs"
- [ testCase "constructs the empty bootstrap ordinarily"
- constructsEmptyBootstrap
- , testCase "identifies comment-only reserved input"
- identifiesCommentOnlyInput
- , testCase "loads and parses the packaged final prelude"
- parsesPackagedFinalPrelude
- , testCase "renders packaged final-prelude failures"
- rendersPackagedPreludeFailures
- , testCase "confines exact foundation-leaf completion"
- confinesFoundationLeafCompletion
- , testCase "builds the confined final prelude"
- buildsConfinedFinalPrelude
- , testCase "publishes the final prelude as an ordinary sealed root"
- publishesFinalPreludeRoot
- , testCase "retains exact omitted-proof locations"
- retainsExactOmittedProofLocation
- , testCase "coalesces syntax without collapsing semantic imports"
- coalescesSharedDirectSyntax
- , testCase "makes selected source errors terminal"
- rejectsUnsupportedTypedSource
- , testCase "reuses one verification session for successive checks"
- reusesVerificationSession
- , testCase "compiles exact declarations across an import"
- compilesExactDeclarationGraph
- , testCase "compiles and imports exact structures"
- compilesExactStructures
- , testCase "compiles and caches contextual abbreviations"
- compilesContextualAbbreviations
- , testCase "rejects an unknown exact structure parent atomically"
- rejectsUnknownExactStructureParent
- , testCase "compiles exact relation expressions"
- compilesExactRelationExpressions
- , testCase "resolves source-owned set application"
- resolvesSourceOwnedApplication
- , testCase "scopes quantified terms in proposition contexts"
- confinesExactQuantifiedTerms
- , testCase "closes the exact definition declaration boundary"
- closesExactDefinitionDeclarationBoundary
- , testCase "compiles exact ordinary proofs"
- compilesExactOrdinaryProofs
- , testCase "restores exact binder and witness proof forms"
- restoresExactBinderAndWitnessProofForms
- , testCase "restores exact local reasoning and calculations"
- restoresExactLocalReasoningAndCalculations
- , testCase "selects calculation link failures by source order"
- selectsCalculationLinkFailureBySourceOrder
- , testCase "compiles and reuses proof-local set definitions"
- compilesAndReusesProofLocalSetDefinitions
- , testCase "compiles and reuses proof-local function graphs"
- compilesAndReusesProofLocalFunctionGraphs
- , testCase "restores exact cases and classical contradiction"
- confinesTerminalExactContradiction
- , testCase "compiles exact separation comprehensions"
- compilesExactSeparationComprehensions
- , testCase "compiles exact replacement comprehensions"
- compilesExactReplacementComprehensions
- , testCase "compiles and reuses relational replacement"
- compilesAndReusesRelationalReplacement
- , testCase "compiles and reuses exact finite sets"
- compilesAndReusesExactFiniteSets
- , testCase "prepares exact deterministic datatypes"
- preparesExactDatatypes
- , testCase "rejects nested exact datatype recursion"
- rejectsNestedExactDatatypeRecursion
- , testCase "compiles and reuses exact datatypes"
- compilesAndReusesExactDatatypes
- , testCase "prepares exact direct inductives"
- preparesExactDirectInductives
- , testCase "prepares nested exact inductive recursion"
- preparesNestedExactInductiveRecursion
- , testCase "compiles transparent nested inductive wrappers"
- compilesTransparentNestedInductiveWrappers
- , testCase "normalizes nested exact inductive contexts"
- normalizesNestedExactInductiveContexts
- , testCase "compiles and reuses exact inductives"
- compilesAndReusesExactInductives
- , testCase "authorizes recursive exact inductives"
- authorizesRecursiveExactInductives
- , testCase "reuses exact separation validation"
- reusesExactSeparationValidation
- , testCase "compiles exact source axioms"
- compilesExactSourceAxioms
- , testCase "does not treat marker-only nouns as the fixed set noun"
- doesNotTreatMarkerOnlyNounAsSet
- , testCase "rejects proof-local generalization"
- rejectsProofLocalGeneralization
- , testCase "restores checked set induction"
- restoresCheckedSetInduction
- , testCase "compiles exact omitted proofs"
- compilesExactOmittedProofs
- , testCase "propagates and reuses exact escape authority"
- reusesExactEscapeAuthority
- , testCase "checks continuations after omitted subclaims"
- rejectsAfterExactOmittedSubclaim
- , testCase "reuses exact proof validation across module misses"
- reusesExactProofValidationAcrossModuleMisses
- , testCase "rejects declarations of fixed semantics"
- rejectsFixedSemanticDeclaration
- , testCase "rejects inductive carriers with fixed semantics"
- rejectsFixedSemanticInductive
- , testCase "keeps exact semantics independent of fixity"
- keepsExactSemanticsIndependentOfFixity
- , testCase "loads a cached exact producer for a fresh importer"
- loadsCachedExactProducerForFreshImporter
- , testCase "reports admitted source escapes on fresh, warm, and failure paths"
- reportsAdmittedSourceEscapes
- , testCase "selects concurrent module failures by source order"
- selectsConcurrentModuleFailureDeterministically
- , testCase "batches independent structure obligations atomically"
- batchesStructureObligationsAtomically
- , testCase "speculates dependent proof obligations without admitting ahead"
- speculatesDependentProofObligationsWithoutAdmittingAhead
- , testCase "starts diamond consumers after sealed acknowledgements"
- schedulesDiamondAfterSealedImports
- , testCase "classifies typed Vampire failures conservatively"
- classifiesTypedVampireFailures
- , testCase "retains the exact prefix before a later failure"
- retainsExactPrefixBeforeFailure
- , testCase "routes every production root through exact checking"
- routesProductionVerification
- , testCase "installs nonempty implicit prelude evidence"
- installsNonemptyImplicitPreludeEvidence
- ]
-
-constructsEmptyBootstrap :: Assertion
-constructsEmptyBootstrap = do
- foundation <- expectRight Foundation.checkedFoundation
- result <-
- Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- session <- expectRight result
- let input = Module.bootstrapPreludeInput session
- parsed = Module.identifiedModuleParsed input
- sealed = Module.bootstrapPreludeModule session
- syntax = Module.sealedTypedModuleSyntax sealed
- semantic = Module.sealedTypedModuleSemantic sealed
- assertEqual "reserved owner"
- preludeModuleName
- (Module.identifiedModuleOwner input)
- case Module.identifiedModuleBinding input of
- Module.ReservedModuleBinding fileId label -> do
- assertEqual "diagnostic label"
- Prelude.preludeDiagnosticLabel
- label
- assertEqual "registered display label"
- (Just Prelude.preludeDiagnosticLabel)
- (lookupFilePath fileId)
- assertEqual "registered identity label"
- (Just Prelude.preludeDiagnosticLabel)
- (lookupFileIdentityPath fileId)
- Module.PhysicalModuleBinding source ->
- assertFailure
- ("bootstrap acquired a physical source: " <> show source)
- assertEqual "empty parsed blocks"
- []
- (Parse.identifiedParsedModuleBlocks parsed)
- assertEqual "exact empty source identity"
- (Content.sourceContentIdBytes ByteString.empty)
- (Parse.identifiedParsedModuleSourceContentId parsed)
- assertEqual "no syntax imports"
- []
- (Syntax.moduleSyntaxDirectInputs syntax)
- assertEqual "empty local syntax"
- []
- (Syntax.canonicalSyntaxDeltaEntries
- (Syntax.moduleSyntaxLocalDelta syntax))
- assertEqual "semantic owner"
- preludeModuleName
- (Semantic.semanticInterfaceOwner semantic)
- assertEqual "no semantic imports"
- []
- (Semantic.semanticInterfaceDirectInputs semantic)
- assertEqual "no semantic declarations"
- []
- (Semantic.semanticInterfaceDeclarations semantic)
- expectedPrefix <-
- expectRight
- (Semantic.initialPrefixContextId
- (Identity.theoryId foundation)
- preludeModuleName
- [])
- assertEqual "empty sealed prefix"
- expectedPrefix
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix sealed))
-
-identifiesCommentOnlyInput :: Assertion
-identifiesCommentOnlyInput = do
- emptySource <-
- expectRight
- =<< Prelude.parseReservedPreludeSource
- Prelude.emptyBootstrapSourceInput
- source <-
- expectRight
- (Prelude.reservedPreludeSourceInput
- (Text.encodeUtf8 "% an in-memory comment\n"))
- first <-
- expectRight
- =<< Prelude.parseReservedPreludeSource source
- second <-
- expectRight
- =<< Prelude.parseReservedPreludeSource source
- let emptyParsed = Prelude.reservedParsedPreludeModule emptySource
- firstParsed = Prelude.reservedParsedPreludeModule first
- secondParsed = Prelude.reservedParsedPreludeModule second
- assertEqual "reserved live source binding"
- Parse.FreshReservedSource
- (Parse.freshModuleInputBinding
- (Prelude.reservedParsedPreludeInput first))
- assertEqual "comment-only source has no blocks"
- []
- (Parse.identifiedParsedModuleBlocks firstParsed)
- assertBool "content changes parsed identity"
- (Parse.identifiedParsedModuleId emptyParsed
- /= Parse.identifiedParsedModuleId firstParsed)
- assertEqual "same input has stable parsed identity"
- (Parse.identifiedParsedModuleId firstParsed)
- (Parse.identifiedParsedModuleId secondParsed)
- assertEqual "comments do not change syntax"
- (Syntax.moduleSyntaxAssertedId
- (Parse.identifiedParsedModuleSyntaxInterface emptyParsed))
- (Syntax.moduleSyntaxAssertedId
- (Parse.identifiedParsedModuleSyntaxInterface firstParsed))
-
-parsesPackagedFinalPrelude :: Assertion
-parsesPackagedFinalPrelude = do
- path <- Paths.getDataFileName "data/felix-prelude.tex"
- expectedBytes <- ByteString.readFile path
- source <- expectRight =<< Prelude.loadReservedPreludeSourceInput
- assertEqual "exact packaged bytes"
- expectedBytes
- (Prelude.reservedPreludeSourceBytes source)
- assertEqual "reserved owner"
- preludeModuleName
- (Prelude.reservedPreludeSourceOwner source)
- assertEqual "diagnostic label"
- Prelude.preludeDiagnosticLabel
- (Prelude.reservedPreludeSourceLabel source)
- first <- expectRight =<< Prelude.parseReservedPreludeSource source
- second <- expectRight =<< Prelude.parseReservedPreludeSource source
- let firstInput = Prelude.reservedParsedPreludeInput first
- firstParsed = Prelude.reservedParsedPreludeModule first
- secondParsed = Prelude.reservedParsedPreludeModule second
- assertEqual "no textual imports"
- []
- (Parse.freshModuleInputImports firstInput)
- assertBool "declaration-bearing source"
- (not (null (Parse.identifiedParsedModuleBlocks firstParsed)))
- assertEqual "deterministic syntax interface"
- (Syntax.moduleSyntaxAssertedId
- (Parse.identifiedParsedModuleSyntaxInterface firstParsed))
- (Syntax.moduleSyntaxAssertedId
- (Parse.identifiedParsedModuleSyntaxInterface secondParsed))
-
-rendersPackagedPreludeFailures :: Assertion
-rendersPackagedPreludeFailures = do
- assertEqual "load failure"
- "/missing/felix-prelude.tex: unable to read packaged final prelude: not found"
- (Prelude.renderPreludeLoadError
- (Prelude.PreludeSourceReadFailed
- "/missing/felix-prelude.tex"
- "not found"))
- assertEqual "located syntax failure"
- "<felix-prelude>: syntax pragma location is out of range at 7:3"
- (Prelude.renderPreludeParseError parseFailure)
- assertEqual "authority-free API presentation"
- ("packaged final prelude parsing failed: "
- <> "<felix-prelude>: syntax pragma location is out of range at 7:3")
- (Workspace.renderAuthorityFreeParseError
- (Workspace.AuthorityFreePreludeParseFailed parseFailure))
- where
- parseFailure =
- Prelude.PreludeSyntaxPragmaFailed
- (Pragma.SyntaxPragmaLocationOutOfRange
- Prelude.preludeDiagnosticLabel
- 7
- 3)
-
-confinesFoundationLeafCompletion :: Assertion
-confinesFoundationLeafCompletion = do
- foundation <- expectRight Foundation.checkedFoundation
- packaged <- expectRight =<< Prelude.loadReservedPreludeSourceInput
- parsed <- expectRight =<< Prelude.parseReservedPreludeSource packaged
- matching <- sole "matching foundation claim"
- (take 1
- (Parse.identifiedParsedModuleBlocks
- (Prelude.reservedParsedPreludeModule parsed)))
- mismatchInput <-
- expectRight
- (Prelude.reservedPreludeSourceInput
- (Text.encodeUtf8
- "\\begin{proposition}\\label{not_foundation}\n $\\emptyset = \\emptyset$.\n\\end{proposition}\n"))
- mismatchParsed <-
- expectRight =<< Prelude.parseReservedPreludeSource mismatchInput
- mismatch <- sole "mismatching claim"
- (Parse.identifiedParsedModuleBlocks
- (Prelude.reservedParsedPreludeModule mismatchParsed))
- outcome <-
- Declaration.runModuleDriver
- foundation
- preludeModuleName
- []
- unusedResolver
- Declaration.FreshValidation do
- explicit <-
- admitFoundationClaim
- foundation
- matching
- (Just (Raw.Omitted (locate matching)))
- nonmatching <-
- admitFoundationClaim
- foundation
- mismatch
- Nothing
- committed <-
- admitFoundationClaim
- foundation
- matching
- Nothing
- pure (explicit, nonmatching, committed)
- case outcome of
- Right (Declaration.DriverSucceeded
- (explicit, nonmatching, committed)
- _semantic _prefix _closure) -> do
- case explicit of
- Left ExactProof.ExactProofFoundationLeafRequiresImplicitAuto{} ->
- pure ()
- Left other ->
- assertFailure
- ("explicit foundation result: " <> show other)
- Right{} ->
- assertFailure "explicit foundation proof was accepted"
- batch <- expectRight committed
- case nonmatching of
- Left ExactProof.ExactProofFoundationLeafTargetMismatch{} ->
- pure ()
- Left other ->
- assertFailure
- ("mismatching foundation result: " <> show other)
- Right{} ->
- assertFailure "mismatching foundation claim was accepted"
- assertEqual "foundation tag"
- Foundation.UnivOfContains
- (case Declaration.committedBatchProofValidations batch of
- [record] ->
- case Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate
- record) of
- Authority.CheckedKernelConstruction
- (Authority.FoundationLeaf tag) ->
- tag
- authorization ->
- error
- ("unexpected foundation authorization: "
- <> show authorization)
- records ->
- error
- ("unexpected foundation validation count: "
- <> show (length records)))
- Right Declaration.DriverFailed{} ->
- assertFailure "foundation driver failed"
- Right (Declaration.DriverSealFailed failure _prefix) ->
- assertFailure ("foundation driver did not seal: " <> show failure)
- Left failure ->
- assertFailure ("foundation driver did not open: " <> show failure)
- where
- admitFoundationClaim foundation block proof =
- Declaration.runProspectiveLoweringDriver
- (ExactProof.prepareFinalPreludeFoundationClaim
- foundation block proof) >>= \case
- Left failure -> pure (Left failure)
- Right prepared -> do
- lowered <-
- Declaration.runProspectiveLoweringDriver
- (ExactProof.lowerPreparedFinalPreludeFoundationClaim
- prepared)
- checked <-
- either Declaration.failDeclarationDriver pure lowered
- batch <-
- Declaration.admitCheckedDeclaration
- checked
- ExactProof.authorizeCheckedFinalPreludeFoundationClaim
- pure (Right batch)
-
-buildsConfinedFinalPrelude :: Assertion
-buildsConfinedFinalPrelude = do
- foundation <- expectRight Foundation.checkedFoundation
- FinalPrelude.buildFinalPreludeCandidate
- foundation finalPreludeResolver >>= \case
- FinalPrelude.FinalPreludeBuilt candidate -> do
- assertEqual "confined semantic owner"
- preludeModuleName
- (Semantic.semanticInterfaceOwner
- (FinalPrelude.finalPreludeSemantic candidate))
- assertEqual "confined semantic imports"
- []
- (Semantic.semanticInterfaceDirectInputs
- (FinalPrelude.finalPreludeSemantic candidate))
- let baseDeltas =
- [ delta
- | delta <- Semantic.semanticInterfaceDeclarations
- (FinalPrelude.finalPreludeSemantic candidate)
- , not
- (null
- (Semantic.semanticEnvironmentStructures
- (Semantic.declarationDeltaEnvironment delta)))
- ]
- case baseDeltas of
- [delta] -> do
- assertEqual "base structure has no facts"
- []
- (Semantic.declarationDeltaFacts delta)
- assertEqual "base structure has no propositions"
- []
- (Semantic.declarationDeltaPropositions delta)
- case Semantic.semanticEnvironmentStructures
- (Semantic.declarationDeltaEnvironment delta) of
- [descriptor] -> do
- assertEqual "base structure is metadata-only"
- Nothing
- (Semantic.semanticStructureDescriptorPredicate
- descriptor)
- case Semantic.semanticStructureDescriptorOperations
- descriptor of
- [operation] ->
- case Identity.lookupCheckedObjectContent
- (Semantic.semanticStructureOperationObject
- operation)
- (FinalPrelude.finalPreludeObjects candidate) of
- Just Identity.OpaqueObjectContent{} -> pure ()
- content ->
- assertFailure
- ("expected opaque carrier, got "
- <> show content)
- operations ->
- assertFailure
- ("expected one base operation, got "
- <> show operations)
- descriptors ->
- assertFailure
- ("expected one base descriptor, got "
- <> show descriptors)
- deltas ->
- assertFailure
- ("expected one base structure delta, got "
- <> show (length deltas))
- let role roleName =
- maybe
- (assertFailure
- ("missing final-prelude role "
- <> show roleName))
- pure
- (FinalPrelude.finalPreludePublicRole
- candidate roleName)
- omega <- role FinalPrelude.PreludeOmegaObject
- naturals <- role FinalPrelude.PreludeNaturalsAlias
- assertEqual "naturals expands to Omega"
- omega naturals
- traverse_
- (void . role)
- (Set.toList FinalPrelude.expectedFinalPreludePublicRoles)
- let foundationTags = Set.fromList
- [ tag
- | batch <-
- Declaration.pendingModulePrefixBatches
- (FinalPrelude.finalPreludePrefix candidate)
- , record <-
- Declaration.committedBatchProofValidations batch
- , Authority.CheckedKernelConstruction
- (Authority.FoundationLeaf tag) <-
- [ Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate
- record)
- ]
- ]
- assertBool "protected foundation presentation"
- ( Set.fromList
- [ Foundation.SetExtensionality
- , Foundation.EmptyCharacteristic
- , Foundation.PairSetCharacteristic
- , Foundation.FamilyUnionCharacteristic
- ]
- `Set.isSubsetOf` foundationTags
- )
- assertFinalPreludeFoundationAlias
- candidate
- "pairset_iff"
- Foundation.PairSetCharacteristic
- assertFinalPreludeFoundationAlias
- candidate
- "pow_iff"
- Foundation.PowerSetCharacteristic
- assertRejectsAdditionalOmegaFact candidate
- FinalPrelude.FinalPreludeBuildFailed failure prefix ->
- assertFailure
- ("final prelude failed after "
- <> show
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- <> " declarations: "
- <> show failure)
- FinalPrelude.FinalPreludeBuildOpenFailed failure ->
- assertFailure ("final prelude did not open: " <> show failure)
- FinalPrelude.FinalPreludeSourceLoadFailed failure ->
- assertFailure ("final prelude did not load: " <> show failure)
- FinalPrelude.FinalPreludeSourceParseFailed failure ->
- assertFailure ("final prelude did not parse: " <> show failure)
-
-assertRejectsAdditionalOmegaFact
- :: FinalPrelude.FinalPreludeCandidate
- -> Assertion
-assertRejectsAdditionalOmegaFact candidate = do
- omegaId <-
- case FinalPrelude.finalPreludePublicRole
- candidate FinalPrelude.PreludeOmegaObject of
- Just (FinalPrelude.FinalPreludeObjectRole identity) ->
- pure identity
- role ->
- assertFailure ("unexpected Omega role " <> show role)
- >> fail "unreachable"
- batch <- batchByAlias
- (FinalPrelude.finalPreludePrefix candidate)
- "prelude_omega"
- let delta = Declaration.committedBatchDelta batch
- facts = Semantic.declarationDeltaFacts delta
- aliases = Semantic.declarationDeltaAliases delta
- propositions = Declaration.committedBatchPropositions batch
- certificates <-
- maybe
- (assertFailure "Omega declaration validation is absent"
- >> fail "unreachable")
- (pure . Semantic.declarationValidationRecordCertificates)
- (Declaration.committedBatchDeclarationValidation batch)
- (omegaBody, extensional, descriptor, extraFact, extraProposition,
- extraCertificate) <-
- case (facts, propositions, certificates) of
- ( [_equationFact, extensionalFact]
- , [equationProposition, extensionalProposition]
- , [ _equationCertificate
- , extensionalCertificate
- ]
- ) -> do
- body <- case Core.frozenCoreTerm
- (Identity.checkedPropositionTerm equationProposition) of
- Core.CEq Core.TySet
- (Core.CGlobal identity) candidateBody
- | identity == omegaId -> pure candidateBody
- target ->
- assertFailure
- ("unexpected Omega equation " <> show target)
- >> fail "unreachable"
- constructionDescriptor <-
- case Authority.validationDirectAuthorization
- extensionalCertificate of
- Authority.CheckedKernelConstruction
- (Authority.CheckedSetConstructionExtensionality
- identity candidateDescriptor)
- | identity == omegaId -> pure candidateDescriptor
- authorization ->
- assertFailure
- ("unexpected Omega extensional authority "
- <> show authorization)
- >> fail "unreachable"
- pure
- ( body
- , Identity.checkedPropositionTerm extensionalProposition
- , constructionDescriptor
- , extensionalFact
- , extensionalProposition
- , extensionalCertificate
- )
- (candidateFacts, candidatePropositions, candidateCertificates) ->
- assertFailure
- ("unexpected Omega inventory shape "
- <> show
- ( length candidateFacts
- , length candidatePropositions
- , length candidateCertificates
- ))
- >> fail "unreachable"
- case FinalPrelude.validateOmegaFactInventory
- omegaId omegaBody extensional descriptor
- (facts <> [extraFact])
- aliases
- (propositions <> [extraProposition])
- (certificates <> [extraCertificate]) of
- Left (FinalPrelude.FinalPreludeFactContentMismatch
- "prelude_omega") ->
- pure ()
- result ->
- assertFailure
- ("additional Omega construction fact was accepted: "
- <> show result)
-
-publishesFinalPreludeRoot :: Assertion
-publishesFinalPreludeRoot = do
- foundation <- expectRight Foundation.checkedFoundation
- Temp.withSystemTempDirectory "felix-final-prelude-root" \directory -> do
- let path = directory Posix.</> "store.sqlite"
- theory = Identity.theoryId foundation
- open = do
- (_startup, store) <-
- Store.openStore path theory >>= expectRight
- pure store
- bracket open Store.closeStore \store -> do
- freshMemo <- Store.newStoreMemo store
- session <-
- expectRight
- =<< Module.acquireFinalPreludeSession
- freshMemo store foundation finalPreludeResolver
- let input = Module.finalPreludeInput session
- sealed = Module.finalPreludeModule session
- syntax = Module.sealedTypedModuleSyntax sealed
- semantic = Module.sealedTypedModuleSemantic sealed
- assertEqual "empty store constructs the final-prelude root"
- Module.ModuleRootMiss
- (Module.finalPreludeAcquisition session)
- assertEqual "final prelude owner"
- preludeModuleName
- (Module.identifiedModuleOwner input)
- assertEqual "final prelude has no semantic parents"
- []
- (Semantic.semanticInterfaceDirectInputs semantic)
- warmMemo <- Store.newStoreMemo store
- warmSession <- expectRight
- =<< Module.acquireFinalPreludeSession
- warmMemo store foundation unusedResolver
- let cached = Module.finalPreludeModule warmSession
- assertEqual "persisted final-prelude root is a cache hit"
- Module.ModuleRootHit
- (Module.finalPreludeAcquisition warmSession)
- assertEqual "generic root syntax"
- syntax
- (Module.sealedTypedModuleSyntax cached)
- assertEqual "generic root semantics"
- semantic
- (Module.sealedTypedModuleSemantic cached)
- assertEqual "cached base structure descriptor"
- (semanticStructureDescriptors semantic)
- (semanticStructureDescriptors
- (Module.sealedTypedModuleSemantic cached))
- assertEqual "generic root final prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix sealed))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix cached))
- visits <- Store.storeMemoVisits warmMemo
- assertEqual "cached prelude validates one artifact root"
- 1
- (Store.storeArtifactsValidated visits)
-
-semanticStructureDescriptors
- :: Semantic.SemanticInterface
- -> [Semantic.SemanticStructureDescriptor]
-semanticStructureDescriptors semantic =
- [ descriptor
- | delta <- Semantic.semanticInterfaceDeclarations semantic
- , descriptor <- Semantic.semanticEnvironmentStructures
- (Semantic.declarationDeltaEnvironment delta)
- ]
-
-assertTransparentObjectAlias
- :: Module.SealedTypedModule
- -> Text
- -> Assertion
-assertTransparentObjectAlias sealed name = do
- target <- localObjectAliasTarget sealed name
- assertEqual
- ("transparent object for " <> StrictText.unpack name)
- Identity.TransparentObject
- (Identity.objectIdFamily target)
-
-localObjectKeyTarget
- :: Module.SealedTypedModule
- -> Semantic.SemanticGlobalKey
- -> IO Identity.ObjectId
-localObjectKeyTarget sealed key = do
- binding <- sole
- ("semantic binding for " <> show key)
- [ candidate
- | delta <- localSemanticDeltas sealed
- , candidate <- Semantic.semanticEnvironmentBindings
- (Semantic.declarationDeltaEnvironment delta)
- , Semantic.semanticGlobalBindingKey candidate == key
- ]
- pure
- (Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget binding))
-
-localObjectAliasTarget
- :: Module.SealedTypedModule
- -> Text
- -> IO Identity.ObjectId
-localObjectAliasTarget sealed name = do
- delta <- localDeltaByAlias sealed name
- binding <- sole
- ("semantic binding for " <> StrictText.unpack name)
- (Semantic.semanticEnvironmentBindings
- (Semantic.declarationDeltaEnvironment delta))
- pure
- (Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget binding))
-
-checkedPropositionTermByAlias
- :: Module.SealedTypedModule
- -> Text
- -> IO (Core.FrozenCheckedCore Identity.ObjectId)
-checkedPropositionTermByAlias sealed name = do
- batch <- batchByAlias
- (Module.sealedTypedModulePrefix sealed)
- name
- alias <- sole
- ("semantic alias for " <> StrictText.unpack name)
- [ candidate
- | candidate <- Semantic.declarationDeltaAliases
- (Declaration.committedBatchDelta batch)
- , Semantic.semanticAliasName candidate
- == Semantic.semanticName name
- ]
- occurrence <- sole
- ("semantic fact for " <> StrictText.unpack name)
- [ candidate
- | candidate <- Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch)
- , Semantic.semanticFactFingerprint candidate
- == Semantic.semanticAliasTarget alias
- ]
- proposition <- sole
- ("checked proposition for " <> StrictText.unpack name)
- [ candidate
- | candidate <- Declaration.committedBatchPropositions batch
- , Identity.checkedPropositionId candidate
- == Semantic.semanticFactProposition occurrence
- ]
- pure (Identity.checkedPropositionTerm proposition)
-
-batchByAlias
- :: Declaration.PendingModulePrefix
- -> Text
- -> IO Declaration.CommittedDeclarationBatch
-batchByAlias prefix name =
- sole
- ("declaration batch for " <> StrictText.unpack name)
- [ batch
- | batch <- Declaration.pendingModulePrefixBatches prefix
- , alias <- Semantic.declarationDeltaAliases
- (Declaration.committedBatchDelta batch)
- , Semantic.semanticAliasName alias
- == Semantic.semanticName name
- ]
-
-assertFinalPreludeFoundationAlias
- :: FinalPrelude.FinalPreludeCandidate
- -> Text
- -> Foundation.FoundationAxiomTag
- -> Assertion
-assertFinalPreludeFoundationAlias candidate name tag = do
- batch <- batchByAlias
- (FinalPrelude.finalPreludePrefix candidate)
- name
- fact <- sole
- ("foundation fact " <> StrictText.unpack name)
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch))
- assertEqual
- ("foundation safety for " <> StrictText.unpack name)
- Authority.cleanAuthoritySafety
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority fact))
- validation <- sole
- ("foundation validation for " <> StrictText.unpack name)
- (Declaration.committedBatchProofValidations batch)
- assertEqual
- ("exact foundation authority for " <> StrictText.unpack name)
- (Authority.CheckedKernelConstruction
- (Authority.FoundationLeaf tag))
- (Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate validation))
-
-localDeltaByAlias
- :: Module.SealedTypedModule
- -> Text
- -> IO Semantic.DeclarationInterfaceDelta
-localDeltaByAlias sealed name =
- sole
- ("declaration delta for " <> StrictText.unpack name)
- [ delta
- | delta <- localSemanticDeltas sealed
- , any
- ((== Semantic.semanticName name)
- . Semantic.semanticAliasName)
- (Semantic.declarationDeltaAliases delta)
- ]
-
-localSemanticDeltas
- :: Module.SealedTypedModule
- -> [Semantic.DeclarationInterfaceDelta]
-localSemanticDeltas =
- Semantic.semanticInterfaceDeclarations
- . Module.sealedTypedModuleSemantic
-
-retainsExactOmittedProofLocation :: Assertion
-retainsExactOmittedProofLocation = do
- foundation <- expectRight Foundation.checkedFoundation
- source <-
- expectRight
- (Prelude.reservedPreludeSourceInput
- (Text.encodeUtf8
- (StrictText.unlines
- [ "\\begin{proposition}\\label{omitted_location}"
- , " For all $x$ we have $x = x$."
- , "\\end{proposition}"
- , "\\begin{proof}"
- , " Omitted."
- , "\\end{proof}"
- ])))
- parsed <- expectRight =<< Prelude.parseReservedPreludeSource source
- let blocks =
- Parse.identifiedParsedModuleBlocks
- (Prelude.reservedParsedPreludeModule parsed)
- claim <- sole "omitted claim"
- [ block
- | block@Raw.BlockClaim{} <- blocks
- ]
- proof <- sole "omitted proof"
- [ sourceProof
- | Raw.BlockProof _location sourceProof _end <- blocks
- ]
- outcome <-
- Declaration.runModuleDriver
- foundation
- preludeModuleName
- []
- unusedResolver
- Declaration.FreshValidation do
- Declaration.runProspectiveLoweringDriver
- (ExactProof.prepareExactProof claim (Just proof))
- >>= either Declaration.failModuleDriver pure
- case outcome of
- Right (Declaration.DriverSucceeded
- prepared _semantic prefix _closure) -> do
- location <-
- maybe
- (assertFailure "prepared omitted proof lost its location")
- pure
- (ExactProof.preparedExactProofFirstOmission prepared)
- assertEqual "omitted source line" 5 (locLine location)
- assertBool "preparation publishes no declaration"
- (null (Declaration.pendingModulePrefixBatches prefix))
- Right (Declaration.DriverFailed failure _prefix) ->
- assertFailure ("omitted preparation failed: " <> show failure)
- Right (Declaration.DriverSealFailed failure _prefix) ->
- assertFailure ("omitted preparation did not seal: " <> show failure)
- Left failure ->
- assertFailure ("omitted preparation did not open: " <> show failure)
-
-coalescesSharedDirectSyntax :: Assertion
-coalescesSharedDirectSyntax = do
- foundation <- expectRight Foundation.checkedFoundation
- session <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- root <- getCurrentDirectory
- mounts <-
- expectRight
- =<< prepareSourceMounts
- [ (sourceMountId "project", root)
- , (sourceMountId "library", root Posix.</> "library")
- , (sourceMountId "debug", root Posix.</> "debug")
- ]
- let bootstrapSyntax =
- Module.sealedTypedModuleSyntax
- (Module.bootstrapPreludeModule session)
- syntaxInputs _source = [bootstrapSyntax]
- request <-
- expectRight
- (searchedRoot "test/phase3/typed-shared-root.tex")
- workspace <-
- expectRight
- =<< Parse.parseSourceWorkspaceWithSyntaxInputs
- mounts
- request
- syntaxInputs
- case Parse.parsedWorkspaceModules workspace of
- [firstParsed, secondParsed, rootParsed] -> do
- first <- seal foundation session firstParsed []
- second <- seal foundation session secondParsed []
- assertEqual "distinct modules share one syntax interface"
- (Syntax.moduleSyntaxAssertedId
- (Module.sealedTypedModuleSyntax first))
- (Syntax.moduleSyntaxAssertedId
- (Module.sealedTypedModuleSyntax second))
- assertBool "semantic module owners remain distinct"
- (Module.sealedTypedModuleOwner first
- /= Module.sealedTypedModuleOwner second)
- assertBool "semantic interfaces remain distinct"
- (Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic first)
- /= Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic second))
- let rootSyntax = Parse.parsedModuleSyntaxInterface rootParsed
- assertEqual "root coalesces the shared direct syntax"
- [ Syntax.moduleSyntaxAssertedId bootstrapSyntax
- , Syntax.moduleSyntaxAssertedId
- (Module.sealedTypedModuleSyntax first)
- ]
- (Syntax.moduleSyntaxDirectInputs rootSyntax)
- sealedRoot <-
- seal foundation session rootParsed [first, second]
- assertEqual "root retains both semantic imports"
- [ Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic
- (Module.bootstrapPreludeModule session))
- , Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic first)
- , Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic second)
- ]
- (Semantic.semanticInterfaceDirectInputs
- (Module.sealedTypedModuleSemantic sealedRoot))
- modules ->
- assertFailure
- ("unexpected shared-syntax module count: "
- <> show (length modules))
- where
- seal foundation session parsed direct = do
- input <-
- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness session)
- unusedResolver
- Declaration.FreshValidation
- parsed
- direct)
- Module.runTypedModule input >>= \case
- Module.TypedModuleSucceeded sealed ->
- pure sealed
- Module.TypedModuleOpenFailed{} ->
- assertFailure "empty typed module did not open"
- >> fail "unreachable"
- Module.TypedModuleFailed{} ->
- assertFailure "empty typed module did not seal"
- >> fail "unreachable"
-
-rejectsUnsupportedTypedSource :: Assertion
-rejectsUnsupportedTypedSource = do
- result <-
- (checkFileFresh
- (Provers.vampire
- "vampire"
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- "test/phase3/typed-unsupported.tex")
- case result of
- Right
- ( Verification.VerificationCheckingFailure _report
- (failure@(Verification.VerificationTypedModuleError
- source
- (Module.TypedActionFailed
- (Module.TypedExactCompileFailed
- (Exact.ExactGuardedOpaqueSignature location)))
- prefix))
- , _slowReport
- ) -> do
- assertEqual "failed source"
- "test/phase3/typed-unsupported.tex"
- (safeRelativePathFilePath
- (resolvedSourceRelativePath source))
- assertEqual "unsupported source location line"
- 2
- (locLine location)
- assertEqual "failure retains the initial module prefix"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- let diagnostic =
- Verification.renderVerificationDriverError failure
- assertBool "diagnostic retains resolved source"
- ("project:test/phase3/typed-unsupported.tex"
- `StrictText.isInfixOf` diagnostic)
- assertBool "diagnostic retains best location"
- ("typed-unsupported.tex 2:14"
- `StrictText.isInfixOf` diagnostic)
- assertBool "diagnostic explains the typed failure"
- ("opaque signature cannot have a header assumption"
- `StrictText.isInfixOf` diagnostic)
- Left err ->
- assertFailure ("unexpected verification driver error: " <> show err)
- Right{} ->
- assertFailure "unsupported typed source was admitted"
-
-reusesVerificationSession :: Assertion
-reusesVerificationSession =
- withAcceptedFixtureVampire "felix-session-reuse" \prover -> do
- plan <- Store.planStore Store.FreshTemporaryStore >>= expectRight
- graph <- Workspace.prepareDefaultSourceGraph source >>= expectRight
- Store.withStoreLease plan \lease -> do
- opened <- Verification.withVerificationSession lease \session -> do
- let request = Verification.CheckRequest
- { Verification.checkSourceGraph = graph
- , Verification.checkStoreValidationMode =
- Verification.FreshStoreValidation
- , Verification.checkEffectiveJobs = testSequentialJobs
- , Verification.checkVampire = prover
- , Verification.checkRequestObserver =
- ignoredVerificationRequests
- }
- first <-
- Verification.checkWorkspace session request >>= expectRight
- second <-
- Verification.checkWorkspace session request >>= expectRight
- traverse_
- assertUnsupported
- [ Verification.checkVerificationResult first
- , Verification.checkVerificationResult second
- ]
- void (expectRight opened)
- where
- source = "test/phase3/typed-unsupported.tex"
-
- assertUnsupported = \case
- Verification.VerificationCheckingFailure
- _report
- Verification.VerificationTypedModuleError{} ->
- pure ()
- other ->
- assertFailure
- ("successive session check had unexpected result: "
- <> show other)
-
-compilesExactDeclarationGraph :: Assertion
-compilesExactDeclarationGraph = do
- (_foundation, _bootstrap, workspace, sealedModules) <-
- compileExactFixture "test/phase5/exact-importer.tex"
- assertEqual "dependency-closed module count" 2 (length sealedModules)
- assertEqual "imported-before-importer source order"
- [ "test/phase5/exact-producer.tex"
- , "test/phase5/exact-importer.tex"
- ]
- [ safeRelativePathFilePath
- (resolvedSourceRelativePath
- (Parse.parsedModuleResolved parsed))
- | parsed <- toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace)
- ]
- case sealedModules of
- [producer, importer] -> do
- let producerPrefix = Module.sealedTypedModulePrefix producer
- importerPrefix = Module.sealedTypedModulePrefix importer
- producerBatches =
- Declaration.pendingModulePrefixBatches producerPrefix
- importerBatches =
- Declaration.pendingModulePrefixBatches importerPrefix
- assertEqual "producer declaration batches" 3
- (length producerBatches)
- assertEqual "importer declaration batches" 1
- (length importerBatches)
- assertEqual "producer declaration order"
- [0, 1, 2]
- [ localDeclarationOrdinalValue
- (Semantic.declarationSlotOrdinal
- (Declaration.committedBatchSlot batch))
- | batch <- producerBatches
- ]
-
- let producerDeltas =
- Semantic.semanticInterfaceDeclarations
- (Module.sealedTypedModuleSemantic producer)
- importerDeltas =
- Semantic.semanticInterfaceDeclarations
- (Module.sealedTypedModuleSemantic importer)
- assertEqual "one exact binding per producer declaration"
- [1, 1, 1]
- (bindingCount <$> producerDeltas)
- assertEqual "one exact importer binding"
- [1]
- (bindingCount <$> importerDeltas)
- assertEqual "producer object families"
- ["opaque", "transparent"]
- [ objectFamilyName
- (Identity.assertedObjectContent object)
- | batch <- producerBatches
- , object <- Declaration.committedBatchObjects batch
- ]
-
- definitionDelta <- sole "producer definition delta"
- (drop 2 producerDeltas)
- definitionBinding <- sole "producer definition binding"
- (bindings definitionDelta)
- definitionFact <- sole "producer definition fact"
- (Semantic.declarationDeltaFacts definitionDelta)
- definitionAlias <- sole "producer definition alias"
- (Semantic.declarationDeltaAliases definitionDelta)
- assertEqual "definition alias"
- (Semantic.semanticName "phase5_definition")
- (Semantic.semanticAliasName definitionAlias)
- assertEqual "definition is proof-search eligible"
- Semantic.SearchEligible
- (Semantic.semanticFactSearchEligibility definitionFact)
- assertEqual "definition authority is clean"
- Authority.cleanAuthoritySafety
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority definitionFact))
- definitionBatch <- sole "producer definition batch"
- (drop 2 producerBatches)
- validation <-
- maybe
- (assertFailure "definition declaration validation is absent"
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation
- definitionBatch)
- certificate <- sole "definition validation certificate"
- (Semantic.declarationValidationRecordCertificates validation)
- assertEqual "direct defining-equation authority"
- (Authority.CheckedKernelConstruction
- (Authority.CheckedDefinitionEquation
- (Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget
- definitionBinding))))
- (Authority.validationDirectAuthorization
- certificate)
-
- aliasDelta <- sole "producer abbreviation delta"
- (take 1 (drop 1 producerDeltas))
- aliasBinding <- sole "producer abbreviation binding"
- (bindings aliasDelta)
- seedDelta <- sole "producer signature delta"
- (take 1 producerDeltas)
- seedBinding <- sole "producer signature binding"
- (bindings seedDelta)
- let seedTarget =
- Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget seedBinding)
- aliasTarget =
- Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget aliasBinding)
- definitionTarget =
- Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget
- definitionBinding)
- assertEqual "abbreviation expands transparently"
- (Semantic.TransparentExpansion
- aliasTarget)
- (Semantic.semanticGlobalBindingTarget aliasBinding)
- assertEqual "definition remains a named global"
- (Semantic.GlobalReference definitionTarget)
- (Semantic.semanticGlobalBindingTarget definitionBinding)
- assertEqual "definition content coalesces with its expansion"
- aliasTarget
- definitionTarget
- assertEqual "coalesced definition adds no object"
- []
- (Declaration.committedBatchObjects definitionBatch)
- aliasBatch <- sole "producer abbreviation batch"
- (take 1 (drop 1 producerBatches))
- aliasObject <- sole "producer abbreviation object"
- (Declaration.committedBatchObjects aliasBatch)
- case Identity.assertedObjectContent aliasObject of
- Identity.TransparentObjectContent _theory _coreType body ->
- assertEqual
- "expanded body retains only the opaque seed"
- (Set.singleton seedTarget)
- (Core.canonicalTermGlobals body)
- content ->
- assertFailure
- ("abbreviation object is not transparent: "
- <> show content)
- importerBatch <- sole "importer declaration batch" importerBatches
- importerDelta <- sole "importer semantic delta" importerDeltas
- importerBinding <- sole "importer binding"
- (bindings importerDelta)
- assertEqual "equal transparent content reuses the producer object"
- (Semantic.semanticGlobalBindingTarget definitionBinding)
- (Semantic.semanticGlobalBindingTarget importerBinding)
- assertEqual "reused transparent content adds no object"
- []
- (Declaration.committedBatchObjects importerBatch)
- modules ->
- assertFailure
- ("unexpected exact module count: " <> show (length modules))
- where
- bindingCount = length . bindings
-
- bindings =
- Semantic.semanticEnvironmentBindings
- . Semantic.declarationDeltaEnvironment
-
- objectFamilyName :: Identity.ObjectContent -> String
- objectFamilyName = \case
- Identity.OpaqueObjectContent{} -> "opaque"
- Identity.TransparentObjectContent{} -> "transparent"
- Identity.IntrinsicObjectContent{} -> "intrinsic"
-
-compilesExactStructures :: Assertion
-compilesExactStructures = do
- foundation <- expectRight Foundation.checkedFoundation
- repository <- getCurrentDirectory
- Temp.withSystemTempDirectory "felix-exact-structures" \directory -> do
- let path = directory Posix.</> "store.sqlite"
- executable = directory Posix.</> "vampire"
- writeAcceptedFixtureVampire executable
- runs <- newIORef (0 :: Int)
- let resolver = countingAcceptedResolver executable runs
- (_startup, store) <-
- Store.openStore path (Identity.theoryId foundation)
- >>= expectRight
- bracket (pure store) Store.closeStore \opened -> do
- prelude <-
- expectRight
- =<< acquireFinalPreludeSession
- opened foundation resolver
- carrierOperation <- sole "base carrier operation"
- [ operation
- | descriptor <- semanticStructureDescriptors
- (Module.sealedTypedModuleSemantic
- (Module.finalPreludeModule prelude))
- , operation <-
- Semantic.semanticStructureDescriptorOperations descriptor
- ]
- mounts <- exactFixtureMounts repository
- workspace <- parseFinalExactWorkspace
- prelude mounts "test/phase5/exact-structure-child.tex"
- sealed <- compileFinalParsedWorkspaceWithResolver
- foundation prelude resolver workspace
- freshRuns <- readIORef runs
- warm <- installAndLoadStructures
- opened foundation prelude workspace sealed
- warmRuns <- readIORef runs
- assertEqual "warm structures preserve descriptors"
- (structureDescriptors <$> sealed)
- (structureDescriptors <$> warm)
- assertEqual "warm structures make no prover calls"
- freshRuns warmRuns
- case sealed of
- [parent, child] -> do
- let parentBatches =
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix parent)
- parentDeltas =
- Semantic.semanticInterfaceDeclarations
- (Module.sealedTypedModuleSemantic parent)
- childBatches =
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix child)
- childDeltas =
- Semantic.semanticInterfaceDeclarations
- (Module.sealedTypedModuleSemantic child)
- parentBatch <- sole "parent structure batch"
- (take 1 parentBatches)
- parentDelta <- sole "parent structure delta"
- (take 1 parentDeltas)
- parentDescriptor <- sole "parent structure descriptor"
- (Semantic.semanticEnvironmentStructures
- (Semantic.declarationDeltaEnvironment parentDelta))
- parentOperation <- sole "parent structure operation"
- (Semantic.semanticStructureDescriptorOperations
- parentDescriptor)
- parentPredicate <-
- maybe
- (assertFailure "parent structure has no predicate"
- >> fail "unreachable")
- pure
- (Semantic.semanticStructureDescriptorPredicate
- parentDescriptor)
- assertEqual "structure object family order"
- ["opaque", "transparent"]
- [ objectFamilyName
- (Identity.assertedObjectContent object)
- | object <- Declaration.committedBatchObjects parentBatch
- ]
- assertEqual "structure fact aliases"
- [ Semantic.semanticName "pointed_set"
- , Semantic.semanticName "pointed_refl"
- ]
- (Semantic.semanticAliasName
- <$> Semantic.declarationDeltaAliases parentDelta)
- definitionFact <- sole "structure definition fact"
- (take 1 (Semantic.declarationDeltaFacts parentDelta))
- definitionTarget <-
- targetForOccurrence parentBatch definitionFact
- assertEqual "pointwise structure definition"
- (Core.CForall Core.TySet
- (Core.CEq Core.TyProp
- (Core.CApp
- (Core.CGlobal parentPredicate)
- (Core.CBound 0))
- (Core.CEq Core.TySet
- (Core.CBound 0)
- (Core.CBound 0))))
- definitionTarget
- validations <-
- maybe
- (assertFailure "structure validation is absent"
- >> fail "unreachable")
- (pure
- . Semantic.declarationValidationRecordCertificates)
- (Declaration.committedBatchDeclarationValidation
- parentBatch)
- case validations of
- definitionValidation : projectionValidation : [] -> do
- assertEqual "structure definition authority"
- (Authority.CheckedKernelConstruction
- (Authority.CheckedDefinitionEquation
- parentPredicate))
- (Authority.validationDirectAuthorization
- definitionValidation)
- projectionFact <- sole
- "structure projection fact"
- (drop 1
- (Semantic.declarationDeltaFacts
- parentDelta))
- assertEqual
- "projection has independent authority"
- (Semantic.semanticFactAuthority projectionFact)
- (Authority.validationTarget
- projectionValidation)
- assertEqual "projection authority is clean"
- Authority.cleanAuthoritySafety
- (Authority.factAuthoritySafety
- (Authority.validationTarget
- projectionValidation))
- records ->
- assertFailure
- ("expected two structure validations, got "
- <> show records)
- assertBool "all parent structure facts are clean"
- (all
- ((== Authority.cleanAuthoritySafety)
- . Authority.factAuthoritySafety
- . Semantic.semanticFactAuthority)
- (Semantic.declarationDeltaFacts parentDelta))
-
- let claimGlobals marker = do
- batch <- batchWithAlias marker parentBatches
- occurrence <- sole (marker <> " occurrence")
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch))
- Core.canonicalTermGlobals
- <$> targetForOccurrence batch occurrence
- carrierGlobals <- claimGlobals "pointed_carrier"
- operationGlobals <- claimGlobals "pointed_operation"
- assertBool "membership uses inherited carrier"
- (Semantic.semanticStructureOperationObject carrierOperation
- `Set.member` carrierGlobals)
- assertBool "implicit and explicit operation share one object"
- (Semantic.semanticStructureOperationObject parentOperation
- `Set.member` operationGlobals)
-
- let assertEquivalentClaim surface explicit = do
- surfaceTerm <-
- checkedPropositionTermByAlias parent surface
- explicitTerm <-
- checkedPropositionTermByAlias parent explicit
- assertEqual
- (StrictText.unpack surface
- <> " uses the inherited carrier")
- explicitTerm
- surfaceTerm
- assertEquivalentClaim
- "pointed_self_member"
- "pointed_self_member_explicit"
- assertEquivalentClaim
- "pointed_self_not_member"
- "pointed_self_not_member_explicit"
- assertEquivalentClaim
- "pointed_self_element"
- "pointed_self_element_explicit"
- assertEquivalentClaim
- "pointed_header_member"
- "pointed_header_member_explicit"
-
- childBatch <- sole "child structure batch" childBatches
- childDelta <- sole "child structure delta" childDeltas
- childDescriptor <- sole "child structure descriptor"
- (Semantic.semanticEnvironmentStructures
- (Semantic.declarationDeltaEnvironment childDelta))
- assertEqual "child allocates no replacement operation"
- []
- (Semantic.semanticStructureDescriptorOperations
- childDescriptor)
- assertEqual "child owns only its transparent predicate"
- ["transparent"]
- [ objectFamilyName
- (Identity.assertedObjectContent object)
- | object <- Declaration.committedBatchObjects childBatch
- ]
- modules ->
- assertFailure
- ("expected parent and child structures, got "
- <> show (length modules))
- where
- installAndLoadStructures store foundation prelude workspace sealed = do
- memo <- Store.newStoreMemo store
- case
- ( toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace)
- , sealed
- ) of
- ([parentParsed, childParsed], [parent, child]) -> do
- cachedParent <- persistAndLoad memo [] parentParsed parent
- cachedChild <- persistAndLoad
- memo [cachedParent] childParsed child
- pure [cachedParent, cachedChild]
- (parsed, modules) ->
- assertFailure
- ("expected two structure installations, got "
- <> show (length parsed)
- <> " parsed and "
- <> show (length modules)
- <> " checked modules")
- >> fail "unreachable"
- where
- preludeModule = Module.finalPreludeModule prelude
-
- persistAndLoad memo parents parsed sealedModule = do
- let input = Module.identifiedPhysicalModule parsed
- syntax = Module.sealedTypedModuleSyntax sealedModule
- semantic = Module.sealedTypedModuleSemantic sealedModule
- key <- expectRight
- (Semantic.moduleArtifactKey
- (Module.identifiedModuleOwner input)
- (Parse.identifiedParsedModuleId
- (Module.identifiedModuleParsed input))
- (Semantic.semanticInterfaceDirectInputs semantic)
- (Identity.theoryId foundation))
- let artifact = Semantic.moduleArtifactResult
- key
- (Syntax.moduleSyntaxAssertedId syntax)
- (Semantic.semanticInterfaceAssertedId semantic)
- acknowledged <- expectRight
- =<< Store.writeSealedModule
- store
- (Module.sealedTypedModulePrefix sealedModule)
- [syntax]
- [semantic]
- artifact
- assertEqual "cached structure artifact acknowledgement"
- artifact acknowledged
- loaded <- expectRight
- =<< Store.loadCachedModuleInstallation
- memo
- store
- key
- (Syntax.moduleSyntaxAssertedId
- (Parse.parsedModuleSyntaxInterface parsed))
- installation <- maybe
- (assertFailure "cached structure installation is absent"
- >> fail "unreachable")
- pure
- loaded
- expectRight
- (Module.cachedSealedTypedModule
- foundation
- (preludeModule : parents)
- installation)
-
- structureDescriptors =
- semanticStructureDescriptors
- . Module.sealedTypedModuleSemantic
-
- objectFamilyName :: Identity.ObjectContent -> String
- objectFamilyName = \case
- Identity.OpaqueObjectContent{} -> "opaque"
- Identity.TransparentObjectContent{} -> "transparent"
- Identity.IntrinsicObjectContent{} -> "intrinsic"
-
- targetForOccurrence batch occurrence =
- maybe
- (assertFailure "structure proposition is absent"
- >> fail "unreachable")
- (pure . Core.frozenCoreTerm . Identity.checkedPropositionTerm)
- (find
- ((== Semantic.semanticFactProposition occurrence)
- . Identity.checkedPropositionId)
- (Declaration.committedBatchPropositions batch))
-
- batchWithAlias marker batches =
- maybe
- (assertFailure ("missing batch alias " <> marker)
- >> fail "unreachable")
- pure
- (find
- (elem (Semantic.semanticName (StrictText.pack marker))
- . fmap Semantic.semanticAliasName
- . Semantic.declarationDeltaAliases
- . Declaration.committedBatchDelta)
- batches)
-
-compilesContextualAbbreviations :: Assertion
-compilesContextualAbbreviations = do
- foundation <- expectRight Foundation.checkedFoundation
- repository <- getCurrentDirectory
- Temp.withSystemTempDirectory "felix-contextual-abbreviation" \directory -> do
- let storePath = directory Posix.</> "store.sqlite"
- executable = directory Posix.</> "vampire"
- relative = "test/phase5/exact-contextual-abbreviation.tex"
- writeAcceptedFixtureVampire executable
- runs <- newIORef (0 :: Int)
- let resolver = countingAcceptedResolver executable runs
- (_startup, store) <-
- Store.openStore storePath (Identity.theoryId foundation)
- >>= expectRight
- bracket (pure store) Store.closeStore \opened -> do
- prelude <-
- expectRight
- =<< acquireFinalPreludeSession
- opened foundation resolver
- mounts <- exactFixtureMounts repository
- workspace <- parseFinalExactWorkspace prelude mounts relative
- sealed <- sole "contextual abbreviation module"
- =<< compileFinalParsedWorkspaceWithResolver
- foundation prelude resolver workspace
- let deltas =
- Semantic.semanticInterfaceDeclarations
- (Module.sealedTypedModuleSemantic sealed)
- contextualTargets =
- [ (identity, requirements)
- | delta <- deltas
- , binding <- Semantic.semanticEnvironmentBindings
- (Semantic.declarationDeltaEnvironment delta)
- , Semantic.ContextualTransparentExpansion
- identity requirements <-
- [Semantic.semanticGlobalBindingTarget binding]
- ]
- assertEqual "contextual target count" 2
- (length contextualTargets)
- requirements <-
- sole "canonical contextual requirement set"
- (nubOrd (snd <$> contextualTargets))
- assertEqual "one structure operation requirement" 1
- (Map.size requirements)
- let batches =
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed)
- traverse_
- (assertReflexiveFact batches)
- [ "phase5_context_dot_explicit"
- , "phase5_context_inherited"
- , "phase5_context_nested"
- , "phase5_context_explicit_unique"
- ]
-
- parsed <- pure (Parse.parsedWorkspaceRootModule workspace)
- let syntax = Module.sealedTypedModuleSyntax sealed
- semantic = Module.sealedTypedModuleSemantic sealed
- key <- expectRight
- (Semantic.moduleArtifactKey
- (moduleName (Parse.parsedModuleAddress parsed))
- (Parse.parsedModuleId parsed)
- (Semantic.semanticInterfaceDirectInputs semantic)
- (Identity.theoryId foundation))
- let artifact =
- Semantic.moduleArtifactResult
- key
- (Syntax.moduleSyntaxAssertedId syntax)
- (Semantic.semanticInterfaceAssertedId semantic)
- void
- (expectRight
- =<< Store.writeSealedModule
- opened
- (Module.sealedTypedModulePrefix sealed)
- [syntax]
- [semantic]
- artifact)
- memo <- Store.newStoreMemo opened
- loaded <- expectRight
- =<< Store.loadCachedModuleInstallation
- memo opened key
- (Syntax.moduleSyntaxAssertedId
- (Parse.parsedModuleSyntaxInterface parsed))
- installation <- maybe
- (assertFailure "contextual cached installation is absent"
- >> fail "unreachable")
- pure
- loaded
- cached <- expectRight
- (Module.cachedSealedTypedModule
- foundation
- [Module.finalPreludeModule prelude]
- installation)
- assertEqual "cached contextual semantic target"
- semantic
- (Module.sealedTypedModuleSemantic cached)
-
- runsBeforeConsumer <- readIORef runs
- consumerWorkspace <-
- parseFinalExactWorkspace prelude mounts
- "test/phase5/exact-contextual-abbreviation-consumer.tex"
- let consumerParsed =
- Parse.parsedWorkspaceRootModule consumerWorkspace
- consumerInput <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.finalPreludeReadiness prelude)
- resolver
- Declaration.FreshValidation
- consumerParsed
- [cached])
- consumer <- Module.runTypedModule consumerInput >>= \case
- Module.TypedModuleSucceeded sealedConsumer ->
- pure sealedConsumer
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("contextual consumer did not open: " <> show failure)
- >> fail "unreachable"
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("contextual consumer did not seal: " <> show failure)
- >> fail "unreachable"
- let consumerTargets =
- [ Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget binding)
- | delta <- localSemanticDeltas consumer
- , binding <- Semantic.semanticEnvironmentBindings
- (Semantic.declarationDeltaEnvironment delta)
- ]
- assertEqual "two contextual consumer declarations" 2
- (length consumerTargets)
- void
- (sole
- "quantified contextual binder matches its explicit parameter"
- (nubOrd consumerTargets))
- runsAfterConsumer <- readIORef runs
- assertEqual "contextual abbreviations require no prover call"
- runsBeforeConsumer runsAfterConsumer
-
- verifyFailure foundation resolver prelude mounts sealed
- "test/phase5/exact-contextual-abbreviation-missing.tex"
- (\case
- Exact.ExactContextualExpansionNotAvailable location _key ->
- assertEqual "missing context line" 5 (locLine location)
- failure ->
- assertFailure
- ("unexpected missing-context failure: "
- <> show failure))
- verifyFailure foundation resolver prelude mounts sealed
- "test/phase5/exact-contextual-abbreviation-ambiguous.tex"
- (\case
- Exact.ExactStructureOperationAmbiguous
- location _symbol objects -> do
- assertEqual "ambiguous operation line" 16
- (locLine location)
- assertEqual "two distinct operation objects" 2
- (length objects)
- failure ->
- assertFailure
- ("unexpected operation ambiguity failure: "
- <> show failure))
- where
- assertReflexiveFact batches marker = do
- batch <- maybe
- (assertFailure ("missing contextual fact " <> marker)
- >> fail "unreachable")
- pure
- (find
- (elem (Semantic.semanticName (StrictText.pack marker))
- . fmap Semantic.semanticAliasName
- . Semantic.declarationDeltaAliases
- . Declaration.committedBatchDelta)
- batches)
- proposition <- sole (marker <> " proposition")
- (Declaration.committedBatchPropositions batch)
- let body = stripClaimEnvelope
- (Core.frozenCoreTerm
- (Identity.checkedPropositionTerm proposition))
- case body of
- Core.CEq _ left right ->
- assertEqual (marker <> " canonical sides") left right
- _ ->
- assertFailure
- (marker <> " did not elaborate to reflexive equality: "
- <> show body)
-
- stripClaimEnvelope = \case
- Core.CForall _ body -> stripClaimEnvelope body
- Core.CImp _ body -> stripClaimEnvelope body
- term -> term
-
- verifyFailure foundation resolver prelude mounts imported relative checkFailure = do
- workspace <- parseFinalExactWorkspace prelude mounts relative
- let parsed = Parse.parsedWorkspaceRootModule workspace
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.finalPreludeReadiness prelude)
- resolver
- Declaration.FreshValidation
- parsed
- [imported])
- Module.runTypedModule input >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactCompileFailed failure))
- _prefix ->
- checkFailure failure
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactProofFailed
- (ExactProof.ExactProofElaborationFailed failure)))
- _prefix ->
- checkFailure failure
- Module.TypedModuleSucceeded{} ->
- assertFailure (relative <> " was unexpectedly accepted")
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- (relative <> " did not open: " <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- (relative <> " failed unexpectedly: " <> show failure)
-
-rejectsUnknownExactStructureParent :: Assertion
-rejectsUnknownExactStructureParent =
- Temp.withSystemTempDirectory "felix-exact-structure-parent" \root -> do
- let relative = "entry.tex"
- path = root Posix.</> relative
- source =
- "\\begin{struct}\\label{known_structure}\n"
- <> " A known structure $X$ is a onesorted structure.\n"
- <> "\\end{struct}\n\n"
- <> "\\begin{struct}\\label{invalid_structure}\n"
- <> " An invalid structure $X$ is a future structure.\n"
- <> "\\end{struct}\n\n"
- <> "\\begin{struct}\\label{future_structure}\n"
- <> " A future structure $X$ is a onesorted structure.\n"
- <> "\\end{struct}\n"
- ByteString.writeFile path
- (Text.encodeUtf8 (StrictText.pack source))
- foundation <- expectRight Foundation.checkedFoundation
- Temp.withSystemTempDirectory "felix-exact-structure-store" \directory -> do
- let storePath = directory Posix.</> "store.sqlite"
- executable = directory Posix.</> "vampire"
- writeAcceptedFixtureVampire executable
- runs <- newIORef (0 :: Int)
- let resolver = countingAcceptedResolver executable runs
- (_startup, store) <-
- Store.openStore storePath (Identity.theoryId foundation)
- >>= expectRight
- bracket (pure store) Store.closeStore \opened -> do
- prelude <-
- expectRight
- =<< acquireFinalPreludeSession
- opened foundation resolver
- mounts <- exactFixtureMounts root
- workspace <- parseFinalExactWorkspace prelude mounts relative
- let parsed = Parse.parsedWorkspaceRootModule workspace
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.finalPreludeReadiness prelude)
- resolver
- Declaration.FreshValidation
- parsed
- [])
- Module.runTypedModule input >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactCompileFailed
- (Exact.ExactStructureNotVisible
- location _phrase)))
- prefix -> do
- assertEqual "unknown parent line" 5 (locLine location)
- assertEqual "only the valid structure was published"
- 1
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Module.TypedModuleSucceeded{} ->
- assertFailure "unknown structure parent was accepted"
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("invalid structure module did not open: "
- <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("unexpected invalid structure failure: "
- <> show failure)
-
-compilesExactRelationExpressions :: Assertion
-compilesExactRelationExpressions = do
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- repository <- getCurrentDirectory
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace
- bootstrap mounts "test/phase5/exact-relation-expression.tex"
- observed <- newIORef []
- withAcceptedFixtureVampire "felix-exact-relation-expression" \prover -> do
- let resolver = Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- claim = Backend.typedProblemClaim problem
- locals = Backend.typedProblemLocalPremises problem
- modifyIORef' observed
- (<> [ [ Backend.supportedPropositionTerm
- (Backend.typedLocalPremiseProposition premise)
- == Backend.supportedPropositionTerm claim
- | premise <- Vector.toList locals
- ]
- ])
- (Provers.runPreparedTypedProver prover prepared)
- void
- (compileParsedWorkspaceWithResolver
- foundation bootstrap resolver workspace)
- assertEqual
- "relation expression is ordered-pair membership"
- [[True]]
- =<< readIORef observed
-
- missingPair <-
- withAcceptedFixtureVampire "felix-exact-relation-expression-missing-pair" \prover ->
- (checkFileFresh
- prover
- "test/phase5/exact-relation-expression-missing-pair.tex")
- case missingPair of
- Right
- ( Verification.VerificationCheckingFailure _report
- (Verification.VerificationTypedModuleError
- _source
- (Module.TypedActionFailed
- (Module.TypedExactProofFailed
- (ExactProof.ExactProofElaborationFailed
- (Exact.ExactGlobalNotVisible location key))))
- prefix)
- , _slowReport
- ) -> do
- assertEqual "missing ordered-pair provider line"
- 2
- (locLine location)
- assertEqual "missing ordered-pair semantic key"
- (Semantic.SemanticExpressionFunction
- (Raw.mixfixPattern Raw.PairSymbol))
- key
- assertEqual "missing provider publishes no declaration"
- 0
- (length (Declaration.pendingModulePrefixBatches prefix))
- Left err ->
- assertFailure
- ("unexpected relation-expression failure: " <> show err)
- Right{} ->
- assertFailure "relation expression without ordered pairing was admitted"
-
-resolvesSourceOwnedApplication :: Assertion
-resolvesSourceOwnedApplication = do
- foundation <- expectRight Foundation.checkedFoundation
- repository <- getCurrentDirectory
- withAcceptedFixtureVampire "felix-exact-application" \prover ->
- Temp.withSystemTempDirectory "felix-exact-application" \directory -> do
- let storePath = directory Posix.</> "store.sqlite"
- resolver = Declaration.vampireResolver
- (Provers.runPreparedTypedProver prover)
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- prelude <-
- expectRight
- =<< acquireFinalPreludeSession
- store foundation resolver
- mounts <- exactFixtureMounts repository
- workspace <- parseFinalExactWorkspace
- prelude mounts "test/phase5/exact-application.tex"
- sealed <- compileFinalParsedWorkspaceWithResolver
- foundation prelude resolver workspace
- root <- case reverse sealed of
- rootModule : _ -> pure rootModule
- [] ->
- assertFailure "application fixture root is absent"
- >> fail "unreachable"
- assertTransparentObjectAlias root "phase5_apply"
- let applyKey = Semantic.SemanticExpressionFunction
- (Raw.mixfixPattern Raw.ApplySymbol)
- applyObject <- localObjectKeyTarget root applyKey
- surface <- checkedPropositionTermByAlias
- root "phase5_application_surface"
- explicit <- checkedPropositionTermByAlias
- root "phase5_application_explicit"
- assertEqual
- "surface and explicit application lower identically"
- explicit
- surface
- assertBool
- "surface application resolves through the declared object"
- (applyObject `Set.member` Core.frozenCoreGlobals surface)
-
- missing <-
- withAcceptedFixtureVampire "felix-exact-application-missing"
- \prover ->
- (checkFileFresh
- prover
- "test/phase5/exact-application-missing.tex")
- case missing of
- Right
- ( Verification.VerificationCheckingFailure _report
- (Verification.VerificationTypedModuleError
- _source
- (Module.TypedActionFailed
- (Module.TypedExactProofFailed
- (ExactProof.ExactProofElaborationFailed
- (Exact.ExactGlobalNotVisible location key))))
- prefix)
- , _slowReport
- ) -> do
- assertEqual "unresolved application line" 2 (locLine location)
- assertEqual "unresolved application key"
- (Semantic.SemanticExpressionFunction
- (Raw.mixfixPattern Raw.ApplySymbol))
- key
- assertEqual "unresolved application publishes no declaration"
- 0
- (length (Declaration.pendingModulePrefixBatches prefix))
- Left failure ->
- assertFailure
- ("unexpected unresolved application failure: " <> show failure)
- Right{} ->
- assertFailure "application without its source binding was admitted"
-
-confinesExactQuantifiedTerms :: Assertion
-confinesExactQuantifiedTerms = do
- foundation <- expectRight Foundation.checkedFoundation
- repository <- getCurrentDirectory
- withAcceptedFixtureVampire "felix-exact-quantified-subject" \prover ->
- Temp.withSystemTempDirectory "felix-quantified-subject" \directory -> do
- let storePath = directory Posix.</> "store.sqlite"
- resolver = Declaration.vampireResolver
- (Provers.runPreparedTypedProver prover)
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- prelude <-
- expectRight
- =<< acquireFinalPreludeSession
- store foundation resolver
- mounts <- exactFixtureMounts repository
- workspace <- parseFinalExactWorkspace
- prelude mounts
- "test/phase5/exact-quantified-subject.tex"
- sealed <- compileFinalParsedWorkspaceWithResolver
- foundation prelude resolver workspace
- root <- case reverse sealed of
- rootModule : _ -> pure rootModule
- [] ->
- assertFailure "quantified-subject root is absent"
- >> fail "unreachable"
- quantified <- checkedPropositionTermByAlias root
- "phase5_quantified_subject"
- explicit <- checkedPropositionTermByAlias root
- "phase5_explicit_quantifier"
- assertEqual
- "quantified noun subject retains its domain constraint"
- explicit
- quantified
-
- propositionWorkspace <- parseFinalExactWorkspace
- prelude mounts
- "test/phase5/exact-quantified-proposition-terms.tex"
- observations <- newIORef []
- let observingResolver =
- Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem
- prepared
- request =
- Provers.preparedTypedProverRequest
- prepared
- modifyIORef' observations
- (<> [ ( Provers.preparedVerificationRequestId
- request
- , Backend.supportedPropositionTerm
- (Backend.typedProblemClaim problem)
- , Backend.typedProblemRoute problem
- , Backend.typedProblemAuxiliaryTag
- <$> Vector.toList
- (Backend.typedProblemAuxiliaries
- problem)
- )
- ])
- (Provers.runPreparedTypedProver
- prover prepared)
- freshModules <-
- compileFinalParsedWorkspaceWithResolver
- foundation prelude observingResolver
- propositionWorkspace
- freshRoot <- case reverse freshModules of
- rootModule : _ -> pure rootModule
- [] ->
- assertFailure
- "quantified proposition-term root is absent"
- >> fail "unreachable"
- let member left right =
- Core.CApp
- (Core.CApp
- (Core.CIntrinsic Core.Member) left)
- right
- memberAtX =
- member (Core.CBound 0) (Core.CBound 1)
- expectedFunctionTarget =
- Core.CForall Core.TySet
- (Core.CEq Core.TySet
- (Core.CBound 0)
- (Core.CBound 0))
- expectedVerbRequestTarget =
- Core.CForall Core.TySet
- (Core.CImp memberAtX memberAtX)
- expectedVerbProposition =
- Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CImp memberAtX memberAtX))
- expectedTargets =
- [ expectedFunctionTarget
- , expectedVerbRequestTarget
- ]
- ordinaryImplicitAuxiliaries =
- [ Foundation.EmptyCharacteristic
- , Foundation.PairSetCharacteristic
- , Foundation.FamilyUnionCharacteristic
- , Foundation.PowerSetCharacteristic
- ]
- freshObservations <- readIORef observations
- assertEqual
- "nested function and verb terms have exact FOF targets"
- [ ( target
- , Backend.RouteFof
- , ordinaryImplicitAuxiliaries
- )
- | target <- expectedTargets
- ]
- [ (target, route, auxiliaries)
- | (_request, target, route, auxiliaries) <-
- freshObservations
- ]
- functionTarget <- checkedPropositionTermByAlias freshRoot
- "phase5_quantified_function_argument"
- verbTarget <- checkedPropositionTermByAlias freshRoot
- "phase5_quantified_verb_argument"
- assertEqual "nested function proposition core"
- expectedFunctionTarget
- (Core.frozenCoreTerm functionTarget)
- assertEqual "nested verb proposition core"
- expectedVerbProposition
- (Core.frozenCoreTerm verbTarget)
- let proofRecords moduleValue =
- concatMap
- Declaration.committedBatchProofValidations
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix moduleValue))
- proofAuthorizations moduleValue =
- Authority.validationDirectAuthorization
- . Semantic.proofValidationRecordCertificate
- <$> proofRecords moduleValue
- case proofAuthorizations freshRoot of
- [ Authority.CheckedSourceProof [_functionRequest]
- , Authority.CheckedSourceProof [_verbRequest]
- ] -> pure ()
- authorizations ->
- assertFailure
- ("unexpected quantified-term authority: "
- <> show authorizations)
- assertBool
- "quantified terms add no escape-backed authority"
- (all
- ((== Authority.cleanAuthoritySafety)
- . Authority.factAuthoritySafety
- . Semantic.semanticFactAuthority)
- (concatMap
- (Semantic.declarationDeltaFacts
- . Declaration.committedBatchDelta)
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix freshRoot))))
-
- traverse_
- (expectRightIO
- . Store.writePendingModulePrefix store
- . Module.sealedTypedModulePrefix)
- freshModules
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmModules <-
- compileParsedWorkspaceWithReadiness
- foundation
- (Module.finalPreludeReadiness prelude)
- unusedResolver
- validation
- propositionWorkspace
- warmRoot <- case reverse warmModules of
- rootModule : _ -> pure rootModule
- [] ->
- assertFailure
- "warm quantified proposition-term root is absent"
- >> fail "unreachable"
- assertEqual "fresh and warm quantified semantic interface"
- (Module.sealedTypedModuleSemantic freshRoot)
- (Module.sealedTypedModuleSemantic warmRoot)
- assertEqual "fresh and warm quantified request authority"
- (proofAuthorizations freshRoot)
- (proofAuthorizations warmRoot)
- assertEqual "fresh and warm quantified prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix freshRoot))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warmRoot))
-
- negative <-
- withAcceptedFixtureVampire "felix-exact-quantified-term-valued"
- \prover ->
- (checkFileFresh
- prover
- "test/phase5/exact-quantified-term-valued.tex")
- case negative of
- Right
- ( Verification.VerificationCheckingFailure _report
- (Verification.VerificationTypedModuleError
- _source
- (Module.TypedActionFailed
- (Module.TypedExactCompileFailed
- (Exact.ExactQuantifiedTermRequiresPropositionContext
- location)))
- prefix)
- , _slowReport
- ) -> do
- assertEqual "term-valued quantified term line"
- 2 (locLine location)
- assertBool "failed term-valued abbreviation publishes no prefix"
- (null (Declaration.pendingModulePrefixBatches prefix))
- Left failure ->
- assertFailure
- ("unexpected term-valued quantified-term failure: "
- <> show failure)
- Right{} ->
- assertFailure "term-valued quantified exact term was admitted"
-
-closesExactDefinitionDeclarationBoundary :: Assertion
-closesExactDefinitionDeclarationBoundary = do
- repository <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- repositoryMounts <- exactFixtureMounts repository
- Temp.withSystemTempDirectory "felix-definition-boundary" \directory -> do
- mounts <- exactFixtureMounts directory
- annotatedText <-
- readFile
- (repository Posix.</>
- "test/phase5/exact-definition-boundary.tex")
- let relative = "entry.tex"
- sourcePath = directory Posix.</> relative
- unannotatedText =
- StrictText.unpack
- (StrictText.replace
- "A set "
- ""
- (StrictText.pack annotatedText))
- writeFile sourcePath annotatedText
- annotatedWorkspace <-
- parseExactWorkspace bootstrap mounts relative
- annotated <- sole "annotated definition module"
- =<< compileParsedWorkspace
- foundation bootstrap annotatedWorkspace
- assertEqual "annotated definition declaration count"
- 4
- (length
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix annotated)))
- assertBool "annotated definitions prepare no Vampire validations"
- (null (proofValidationRecords annotated))
- let annotatedBatches =
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix annotated)
- symbolicBatch <- sole "symbolic primary declaration"
- (take 1 (drop 2 annotatedBatches))
- wrapperBatch <- sole "functional wrapper declaration"
- (take 1 (drop 3 annotatedBatches))
- symbolicObject <- bindingObject "symbolic primary" symbolicBatch
- wrapperObject <- bindingObject "functional wrapper" wrapperBatch
- wrapperContent <- sole "functional wrapper transparent object"
- [ Identity.assertedObjectContent object
- | batch <-
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix annotated)
- , object <- Declaration.committedBatchObjects batch
- , Identity.assertedObjectId object == wrapperObject
- ]
- case wrapperContent of
- Identity.TransparentObjectContent _theory _type body ->
- assertEqual
- "functional wrapper applies the primary symbolic object"
- (Set.singleton symbolicObject)
- (Core.canonicalTermGlobals body)
- content ->
- assertFailure
- ("functional wrapper is not transparent: " <> show content)
-
- writeFile sourcePath unannotatedText
- unannotatedWorkspace <-
- parseExactWorkspace bootstrap mounts relative
- unannotated <- sole "unannotated definition module"
- =<< compileParsedWorkspace
- foundation bootstrap unannotatedWorkspace
- assertEqual
- "canonical set annotations do not change the semantic interface"
- (Module.sealedTypedModuleSemantic unannotated)
- (Module.sealedTypedModuleSemantic annotated)
- assertEqual
- "canonical set annotations do not change declaration identity"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix unannotated))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix annotated))
- assertEqual
- "canonical set annotations do not change direct authority"
- (directDeclarationAuthorizations unannotated)
- (directDeclarationAuthorizations annotated)
-
- let storePath = directory Posix.</> "store.sqlite"
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix annotated))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warm <- sole "warm annotated definition module"
- =<< compileParsedWorkspaceWithValidation
- foundation bootstrap unusedResolver validation
- annotatedWorkspace
- assertEqual "warm annotated semantic interface"
- (Module.sealedTypedModuleSemantic annotated)
- (Module.sealedTypedModuleSemantic warm)
- assertEqual "warm annotated declaration identity"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix annotated))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warm))
- assertEqual "warm annotated direct authority"
- (directDeclarationAuthorizations annotated)
- (directDeclarationAuthorizations warm)
- assertBool "warm annotated definitions run no prover"
- (null (proofValidationRecords warm))
-
- annotationFailure <- exactFailure foundation bootstrap repositoryMounts
- "test/phase5/exact-definition-annotation-failure.tex"
- case annotationFailure of
- ( Exact.ExactNonCanonicalSetDefinitionAnnotation location
- , prefix
- ) -> do
- assertEqual "nontrivial annotation line" 2 (locLine location)
- assertBool "nontrivial annotation publishes no prefix"
- (null (Declaration.pendingModulePrefixBatches prefix))
- assertBool "annotation diagnostic gives the explicit migration"
- ("total condition in the definiens"
- `StrictText.isInfixOf`
- Exact.renderExactCompileError
- (fst annotationFailure))
- (failure, _prefix) ->
- assertFailure
- ("unexpected annotation failure: " <> show failure)
-
- aliasFailure <- exactFailure foundation bootstrap repositoryMounts
- "test/phase5/exact-definition-alias-failure.tex"
- case aliasFailure of
- (Exact.ExactDefinitionCombinedSymbolicAlias location, prefix) -> do
- assertEqual "combined symbolic alias line" 2 (locLine location)
- assertBool "combined symbolic alias publishes no prefix"
- (null (Declaration.pendingModulePrefixBatches prefix))
- assertBool "combined alias diagnostic gives the wrapper migration"
- ("define the symbolic operator first"
- `StrictText.isInfixOf`
- Exact.renderExactCompileError (fst aliasFailure))
- (failure, _prefix) ->
- assertFailure
- ("unexpected combined-alias failure: " <> show failure)
-
- guardFailure <- exactFailure foundation bootstrap repositoryMounts
- "test/phase5/exact-definition-guard-failure.tex"
- case guardFailure of
- (Exact.ExactGuardedTransparentDefinition location, prefix) -> do
- assertEqual "guarded definition line" 2 (locLine location)
- assertBool "guarded definition publishes no prefix"
- (null (Declaration.pendingModulePrefixBatches prefix))
- assertBool "guard diagnostic gives the total-definition migration"
- ("where a corresponding opaque signature form exists"
- `StrictText.isInfixOf`
- Exact.renderExactCompileError (fst guardFailure))
- (failure, _prefix) ->
- assertFailure
- ("unexpected guarded-definition failure: " <> show failure)
-
- assertRussellSetAnnotation bootstrap repository
- where
- proofValidationRecords moduleValue =
- concatMap
- Declaration.committedBatchProofValidations
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix moduleValue))
-
- directDeclarationAuthorizations moduleValue =
- [ Authority.validationDirectAuthorization certificate
- | batch <-
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix moduleValue)
- , validation <-
- maybeToList
- (Declaration.committedBatchDeclarationValidation batch)
- , certificate <-
- Semantic.declarationValidationRecordCertificates validation
- ]
-
- bindingObject label batch = do
- binding <- sole (label <> " semantic binding")
- (Semantic.semanticEnvironmentBindings
- (Semantic.declarationDeltaEnvironment
- (Declaration.committedBatchDelta batch)))
- pure
- (Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget binding))
-
- exactFailure foundation bootstrap mounts relative = do
- workspace <- parseExactWorkspace bootstrap mounts relative
- parsed <- sole "failed exact definition module"
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- unusedResolver
- Declaration.FreshValidation
- parsed
- [])
- Module.runTypedModule input >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactCompileFailed failure))
- prefix ->
- pure (failure, prefix)
- result ->
- assertFailure
- (case result of
- Module.TypedModuleSucceeded{} ->
- "expected exact definition failure, but the module succeeded"
- Module.TypedModuleOpenFailed{} ->
- "expected exact definition failure, but the module did not open"
- Module.TypedModuleFailed{} ->
- "expected an exact compile failure, but checking failed differently")
- >> fail "unreachable"
-
- assertRussellSetAnnotation bootstrap repository = do
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace
- bootstrap mounts "test/examples/russell.tex"
- parsed <- sole "Russell parity module"
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- case Parse.identifiedParsedModuleBlocks
- (Module.identifiedModuleParsed
- (Module.identifiedPhysicalModule parsed)) of
- Raw.BlockDefn _location _title _marker
- (Raw.Defn []
- (Raw.DefnAdj
- (Just (Raw.NounPhrase
- [] (Raw.Noun _ noun []) Nothing [] Nothing))
- _subject _adjective)
- _statement) : _ ->
- assertBool "Russell uses the canonical built-in set noun"
- (Lexicon.isBuiltinSetNoun noun)
- _ ->
- assertFailure
- "Russell source does not retain its annotated adjective head"
-
-compilesExactOrdinaryProofs :: Assertion
-compilesExactOrdinaryProofs =
- Temp.withSystemTempDirectory "felix-exact-proofs" \root -> do
- repository <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace
- bootstrap mounts "test/phase5/exact-proofs.tex"
- let executable = root Posix.</> "vampire"
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for exact-proof'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- observations <- newIORef []
- let resolver = Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- claim =
- Backend.typedProblemClaim problem
- locals =
- Backend.typedProblemLocalPremises problem
- modifyIORef' observations
- (<> [ ( Vector.length
- (Backend.typedProblemGlobalPremises problem)
- , Vector.length
- locals
- , [ Vector.length
- (Backend.supportedPropositionSupport
- (Backend.typedLocalPremiseProposition premise))
- | premise <- Vector.toList locals
- ]
- , [ Backend.supportedPropositionTerm
- (Backend.typedLocalPremiseProposition premise)
- == Backend.supportedPropositionTerm claim
- | premise <- Vector.toList locals
- ]
- )
- ])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- sealed <-
- compileParsedWorkspaceWithResolver
- foundation bootstrap resolver workspace
- rootModule <- sole "exact proof root" (drop 1 sealed)
- let batches =
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix rootModule)
- assertEqual "one definition and five theorem declarations"
- 6
- (length batches)
- let proofBatches = drop 1 batches
- assertEqual "only closed theorem facts are published"
- [1, 1, 1, 1, 1]
- [ length
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch))
- | batch <- proofBatches
- ]
- assertEqual "proof request aggregation follows source structure"
- [1, 2, 2, 1, 1]
- [ case Declaration.committedBatchProofValidations batch of
- [record] ->
- case Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate
- record) of
- Authority.CheckedSourceProof requests ->
- length requests
- authorization ->
- error
- ("unexpected exact proof authority: "
- <> show authorization)
- records ->
- error
- ("unexpected exact proof validation count: "
- <> show (length records))
- | batch <- proofBatches
- ]
- headerBatch <- sole "header-envelope proof batch"
- (take 1 (drop 3 proofBatches))
- headerProposition <- sole "header-envelope checked proposition"
- (Declaration.committedBatchPropositions headerBatch)
- assertEqual "header-envelope closed target"
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CImp
- (member
- (Core.CBound 0)
- (Core.CBound 1))
- (member
- (Core.CBound 0)
- (Core.CBound 1)))))
- (Core.frozenCoreTerm
- (Identity.checkedPropositionTerm headerProposition))
- headerFact <- sole "header-envelope published fact"
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta headerBatch))
- assertEqual "header-envelope proof remains clean"
- Authority.cleanAuthoritySafety
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority headerFact))
- observed <- readIORef observations
- case observed of
- (implicitGlobals, 0, [], [])
- : [ (0, 1, [1], _structuralMatches)
- , (1, 2, [1, 1], _subclaimMatches)
- , (0, 0, [], [])
- , (0, 1, [1], _followingMatches)
- , (0, 1, [2], [True])
- , (generalizedGlobals, 0, [], [])
- ] -> do
- assertBool "implicit Auto selects visible FOF facts"
- (implicitGlobals > 0)
- assertBool "generalized Auto selects visible FOF facts"
- (generalizedGlobals > 0)
- _ ->
- assertFailure
- ("unexpected exact proof premise policies: "
- <> show observed)
- where
- member element set =
- Core.CApp
- (Core.CApp
- (Core.CIntrinsic Core.Member)
- element)
- set
-
-restoresExactBinderAndWitnessProofForms :: Assertion
-restoresExactBinderAndWitnessProofForms =
- Temp.withSystemTempDirectory "felix-exact-proof-parity" \root -> do
- repository <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace
- bootstrap mounts "test/phase5/exact-proof-parity.tex"
- parsed <- sole "parsed proof-parity module"
- (toList (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- let blocks =
- Parse.identifiedParsedModuleBlocks
- (Parse.parsedModuleIdentified parsed)
- claims = [claim | claim@Raw.BlockClaim{} <- blocks]
- proofs =
- [ proof
- | Raw.BlockProof _location proof _end <- blocks
- ]
- omittedClaim <-
- case reverse claims of
- claim : _ -> pure claim
- [] -> assertFailure "missing omitted witness claim"
- >> fail "unreachable"
- omittedProof <-
- case reverse proofs of
- proof : _ -> pure proof
- [] -> assertFailure "missing omitted witness proof"
- >> fail "unreachable"
- Declaration.runModuleDriver
- foundation
- preludeModuleName
- []
- unusedResolver
- Declaration.FreshValidation do
- Declaration.runProspectiveLoweringDriver
- (ExactProof.prepareExactProof
- omittedClaim (Just omittedProof))
- >>= either Declaration.failModuleDriver pure
- >>= \case
- Right (Declaration.DriverSucceeded
- prepared _semantic _prefix _closure) ->
- case ExactProof.preparedExactProofFirstOmission prepared of
- Just location ->
- assertEqual "nested Take retains first omission"
- 106 (locLine location)
- Nothing ->
- assertFailure "nested Take lost its omission"
- Right Declaration.DriverFailed{} ->
- assertFailure "omitted witness preparation failed"
- Right Declaration.DriverSealFailed{} ->
- assertFailure "omitted witness preparation did not seal"
- Left failure ->
- assertFailure
- ("omitted witness preparation did not open: "
- <> show failure)
- let executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for exact-proof-parity'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- observations <- newIORef []
- fresh <-
- sole "proof-parity module"
- =<< compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- (observingAcceptedResolver executable observations)
- Declaration.FreshValidation
- workspace
- observed <- readIORef observations
- assertEqual "restored proof request count" 17 (length observed)
- assertEqual
- "restored proof declarations preserve discharge order"
- [1, 1, 1, 1, 1, 1, 3, 2, 2, 3, 1]
- (proofRequestCounts fresh)
- case observed of
- first : second : third : fourth : _rest -> do
- assertGuardRequest "single bounded fix" 2 first
- assertGuardRequest "multiple bounded fix" 3 second
- assertGuardRequest "negative bounded fix" 2 third
- assertGuardRequest "fix such that" 2 fourth
- _ -> assertFailure "missing bounded-fix requests"
- case drop 4 observed of
- leftFirst : rightFirst : _ -> do
- assertSequentialAssumptions "left conjunct first" leftFirst
- assertSequentialAssumptions "right conjunct first" rightFirst
- _ -> assertFailure "missing conjunction-assumption requests"
- assertTakeSequence "bounded TakeVar" (drop 6 observed)
- assertTakeSequence "existential Have" (drop 13 observed)
- case drop 9 observed of
- namedDischarge : _namedFinal : anonymousDischarge : _ -> do
- assertExactDischarge "named noun" namedDischarge
- assertEqual "named noun opens two witness binders"
- 2
- (leadingExistentials
- (observedClaimTerm namedDischarge))
- assertExactDischarge "anonymous noun" anonymousDischarge
- assertEqual "anonymous noun opens one unnameable binder"
- 1
- (leadingExistentials
- (observedClaimTerm anonymousDischarge))
- _ -> assertFailure "missing noun-witness requests"
- lastBatch <-
- case reverse
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix fresh)) of
- batch : _ -> pure batch
- [] -> assertFailure "missing restored-proof batches"
- >> fail "unreachable"
- lastFact <- sole "omitted witness fact"
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta lastBatch))
- assertEqual "omitted continuation remains escape-backed"
- (Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.Omitted))
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority lastFact))
- assertBool "proof-local witnesses publish no objects"
- (all
- (null . Declaration.committedBatchObjects)
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix fresh)))
-
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmRuns <- newIORef (0 :: Int)
- warm <-
- sole "warm proof-parity module"
- =<< compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- (countingAcceptedResolver executable warmRuns)
- validation
- workspace
- assertEqual "warm restored proofs skip Vampire"
- 0 =<< readIORef warmRuns
- assertEqual
- "fresh and warm proof validation keys and authority"
- (proofValidationRecords fresh)
- (proofValidationRecords warm)
- assertEqual
- "fresh and warm checked proposition identities"
- (map Identity.checkedPropositionId
- (concatMap Declaration.committedBatchPropositions
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix fresh))))
- (map Identity.checkedPropositionId
- (concatMap Declaration.committedBatchPropositions
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix warm))))
-
- assertProofParityFailure
- foundation bootstrap mounts
- "test/phase5/exact-proof-parity-invalid-fix.tex"
- (\case
- ExactProof.ExactProofGoalStatementMismatch location ->
- locLine location == 6
- _ -> False)
- assertProofParityFailure
- foundation bootstrap mounts
- "test/phase5/exact-proof-parity-invalid-fix-shape.tex"
- (\case
- ExactProof.ExactProofExpectedUniversalGoal location ->
- locLine location == 6
- _ -> False)
- assertProofParityFailure
- foundation bootstrap mounts
- "test/phase5/exact-proof-parity-invalid-assume.tex"
- (\case
- ExactProof.ExactProofGoalStatementMismatch location ->
- locLine location == 6
- _ -> False)
- where
- observingAcceptedResolver executable observations =
- Declaration.vampireResolver \prepared -> do
- let problem = Provers.preparedTypedProverLogicalProblem prepared
- claim = Backend.typedProblemClaim problem
- locals = Backend.typedProblemLocalPremises problem
- observation =
- ProofParityObservation
- (snd <$> Vector.toList
- (Backend.supportedPropositionSupport claim))
- (Backend.supportedPropositionTerm claim)
- [ ( Backend.localPremiseOrdinalValue
- (Backend.typedLocalPremiseOrdinal premise)
- , snd <$> Vector.toList
- (Backend.supportedPropositionSupport
- (Backend.typedLocalPremiseProposition
- premise))
- , Backend.supportedPropositionTerm
- (Backend.typedLocalPremiseProposition premise)
- )
- | premise <- Vector.toList locals
- ]
- modifyIORef' observations (<> [observation])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
-
- assertGuardRequest label supportCount observation = do
- assertEqual (label <> " support")
- supportCount
- (length (observedClaimSupport observation))
- case observedLocals observation of
- [(_ordinal, _support, local)] ->
- assertEqual (label <> " exact guard")
- (observedClaimTerm observation)
- local
- locals ->
- assertFailure
- (label <> ": expected one guard, found "
- <> show (length locals))
-
- assertTakeSequence label observations =
- case observations of
- discharge : continuation : _ -> do
- assertExactDischarge label discharge
- assertEqual (label <> " continuation premise ordinals")
- [0, 1]
- [ ordinal
- | (ordinal, _support, _term) <-
- observedLocals continuation
- ]
- assertEqual (label <> " continuation witness support")
- 2
- (length (observedClaimSupport continuation))
- _ -> assertFailure (label <> ": missing request sequence")
-
- assertSequentialAssumptions label observation = do
- assertEqual (label <> " premise ordinals")
- [0, 1]
- [ ordinal
- | (ordinal, _support, _term) <- observedLocals observation
- ]
- case observedLocals observation of
- (_ordinal, _support, first) : _ ->
- assertEqual (label <> " retained source order")
- (observedClaimTerm observation)
- first
- [] -> assertFailure (label <> ": no scoped assumptions")
-
- assertExactDischarge label discharge =
- case observedLocals discharge of
- [(_ordinal, _support, local)] ->
- assertEqual (label <> " exact existential discharge")
- (observedClaimTerm discharge)
- local
- locals ->
- assertFailure
- (label <> ": unexpected discharge premises "
- <> show (length locals))
-
- proofRequestCounts sealed =
- [ case Declaration.committedBatchProofValidations batch of
- [record] ->
- case Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate record) of
- Authority.CheckedSourceProof requests -> length requests
- Authority.OmittedAuthorization -> 1
- authorization ->
- error ("unexpected restored-proof authority: "
- <> show authorization)
- records ->
- error ("unexpected restored-proof validation count: "
- <> show (length records))
- | batch <- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed)
- ]
-
- proofValidationRecords sealed =
- concatMap Declaration.committedBatchProofValidations
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed))
-
- leadingExistentials
- :: Core.CanonicalTerm Identity.ObjectId
- -> Int
- leadingExistentials = \case
- Core.CImp
- (Core.CForall Core.TySet
- (Core.CImp body Core.CFalsum))
- Core.CFalsum ->
- 1 + leadingExistentials body
- _ -> 0
-
-data ProofParityObservation = ProofParityObservation
- { observedClaimSupport :: ![Core.CoreType]
- , observedClaimTerm :: !(Core.CanonicalTerm Identity.ObjectId)
- , observedLocals ::
- ![(Natural, [Core.CoreType], Core.CanonicalTerm Identity.ObjectId)]
- }
-
-restoresExactLocalReasoningAndCalculations :: Assertion
-restoresExactLocalReasoningAndCalculations =
- Temp.withSystemTempDirectory "felix-exact-local-reasoning" \root -> do
- repository <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace
- bootstrap mounts "test/phase5/exact-proof-local-reasoning.tex"
- let executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- writeAcceptedFixtureVampire executable
- observations <- newIORef []
- fresh <-
- sole "exact local-reasoning module"
- =<< compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- (observingResolver executable observations)
- Declaration.FreshValidation
- workspace
- observed <- readIORef observations
- assertEqual "local-reasoning request count" 16 (length observed)
- assertEqual "proof forms retain source request order"
- [2, 3, 3, 2, 2, 3, 1]
- (requestCounts fresh)
- case observed of
- sufficesImplication : sufficesReduction
- : equalityFirst : equalitySecond : equalityContinuation
- : biconditionalFirst : biconditionalSecond
- : biconditionalContinuation
- : quantifiedLink : quantifiedContinuation
- : sinceStructuralClaim : sinceStructuralContinuation
- : sinceDischarge : sinceClaim : sinceContinuation
- : _omittedSufficesImplication
- : [] -> do
- case localReasoningTarget sufficesImplication of
- Core.CImp antecedent conclusion -> do
- assertEqual
- "Suffices implication starts from the reduction"
- (localReasoningTarget sufficesReduction)
- antecedent
- assertBool
- "Suffices keeps its distinct current goal as conclusion"
- (conclusion /= antecedent)
- implication ->
- assertFailure
- ("expected Suffices implication, found "
- <> show implication)
- assertEqual "first equality link uses its destination citation"
- 1 (localReasoningGlobalCount equalityFirst)
- assertEqual "second equality link uses local-only justification"
- 0 (localReasoningGlobalCount equalitySecond)
- assertDerivedContinuation
- "equality calculation"
- [0, 1]
- (localReasoningTarget equalityContinuation)
- equalityContinuation
- assertPairwiseDistinct
- "equality links and endpoint"
- [ localReasoningTarget equalityFirst
- , localReasoningTarget equalitySecond
- , localReasoningTarget equalityContinuation
- ]
- assertEqual "first biconditional link remains proposition equality"
- Core.TyProp
- (equalityOperandType
- (localReasoningTarget biconditionalFirst))
- assertDerivedContinuation
- "biconditional calculation"
- [0]
- (localReasoningTarget biconditionalContinuation)
- biconditionalContinuation
- assertPairwiseDistinct
- "biconditional links and endpoint"
- [ localReasoningTarget biconditionalFirst
- , localReasoningTarget biconditionalSecond
- , localReasoningTarget biconditionalContinuation
- ]
- assertEqual "quantified calculation closes both binders"
- 2
- (leadingForalls
- (localReasoningTarget quantifiedLink))
- assertQuantifiedCalculationGuard
- (localReasoningTarget quantifiedLink)
- assertDerivedContinuation
- "quantified calculation"
- [0]
- (localReasoningTarget quantifiedLink)
- quantifiedContinuation
- assertEqual
- "quantified source goal and derived local retain the same guard shape"
- (quantifiedCalculationShape
- (localReasoningTarget quantifiedContinuation))
- (quantifiedCalculationShape
- (localReasoningTarget quantifiedLink))
- assertQuantifiedCalculationGuard
- (localReasoningTarget quantifiedContinuation)
- assertEqual "structural Since submits no premise discharge"
- [0]
- (localReasoningLocalOrdinals sinceStructuralClaim)
- assertEqual "structural Since does not duplicate its premise"
- [0, 1]
- (localReasoningLocalOrdinals
- sinceStructuralContinuation)
- assertEqual "ATP-backed Since starts from existing locals only"
- [0]
- (localReasoningLocalOrdinals sinceDischarge)
- assertEqual "Since claim sees the admitted discourse premise"
- [0, 1]
- (localReasoningLocalOrdinals sinceClaim)
- assertEqual "Since continuation sees premise then claim"
- [0, 1, 2]
- (localReasoningLocalOrdinals sinceContinuation)
- assertEqual "local-only Since requests select no globals"
- [0, 0, 0]
- (localReasoningGlobalCount
- <$> [sinceDischarge, sinceClaim, sinceContinuation])
- assertEqual "biconditional second link keeps local-only policy"
- 0 (localReasoningGlobalCount biconditionalSecond)
- _ ->
- assertFailure
- ("unexpected local-reasoning observations: "
- <> show observed)
- omittedBatch <- sole "omitted Suffices batch"
- (take 1
- (reverse
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix fresh))))
- omittedFact <- sole "omitted Suffices fact"
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta omittedBatch))
- assertEqual "Suffices continuation omission reaches final authority"
- (Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.Omitted))
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority omittedFact))
-
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmRuns <- newIORef (0 :: Int)
- warm <-
- sole "warm local-reasoning module"
- =<< compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- (countingAcceptedResolver executable warmRuns)
- validation
- workspace
- assertEqual "warm local-reasoning validation skips Vampire"
- 0 =<< readIORef warmRuns
- assertEqual "fresh and warm local-reasoning validations"
- (validationRecords fresh)
- (validationRecords warm)
-
- assertRejectedPrefix
- "Suffices implication failure" foundation bootstrap workspace
- executable 0 0 1
- assertRejectedPrefix
- "Suffices reduction failure" foundation bootstrap workspace
- executable 1 0 2
- assertRejectedPrefix
- "middle calculation link failure" foundation bootstrap workspace
- executable 3 1 4
- where
- observingResolver executable observations =
- Declaration.vampireResolver \prepared -> do
- let problem = Provers.preparedTypedProverLogicalProblem prepared
- claim = Backend.typedProblemClaim problem
- locals = Backend.typedProblemLocalPremises problem
- observation =
- LocalReasoningObservation
- { localReasoningTarget =
- Backend.supportedPropositionTerm claim
- , localReasoningGlobalCount = Vector.length
- (Backend.typedProblemGlobalPremises problem)
- , localReasoningLocalOrdinals =
- [ Backend.localPremiseOrdinalValue
- (Backend.typedLocalPremiseOrdinal premise)
- | premise <- Vector.toList locals
- ]
- , localReasoningLocalTerms =
- [ Backend.supportedPropositionTerm
- (Backend.typedLocalPremiseProposition premise)
- | premise <- Vector.toList locals
- ]
- , localReasoningAuxiliaries =
- Backend.typedProblemAuxiliaryTag
- <$> Vector.toList
- (Backend.typedProblemAuxiliaries problem)
- }
- modifyIORef' observations (<> [observation])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
-
- requestCounts sealed =
- [ case Declaration.committedBatchProofValidations batch of
- [record] ->
- case Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate record) of
- Authority.CheckedSourceProof requests -> length requests
- Authority.OmittedAuthorization -> 1
- direct -> error
- ("unexpected local-reasoning authority: " <> show direct)
- records -> error
- ("unexpected local-reasoning validation count: "
- <> show (length records))
- | batch <- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed)
- ]
-
- validationRecords =
- concatMap Declaration.committedBatchProofValidations
- . Declaration.pendingModulePrefixBatches
- . Module.sealedTypedModulePrefix
-
- assertDerivedContinuation
- label expectedOrdinals expectedEndpoint continuation = do
- assertEqual (label <> " local source ordinals")
- expectedOrdinals
- (localReasoningLocalOrdinals continuation)
- case reverse (localReasoningLocalTerms continuation) of
- derived : _ ->
- assertEqual (label <> " derived endpoint")
- expectedEndpoint derived
- [] ->
- assertFailure
- (label <> ": continuation has no derived endpoint")
-
- assertPairwiseDistinct label terms =
- assertEqual (label <> ": " <> show terms)
- (length terms)
- (Set.size (Set.fromList terms))
-
- assertQuantifiedCalculationGuard proposition =
- case dropForalls 2 proposition of
- Core.CImp constraint endpoint -> do
- assertEqual "quantified guard retains both membership bounds"
- 2 (countIntrinsic Core.Member constraint)
- assertEqual "quantified guard retains its such-that equality"
- 1 (countSetEqualities constraint)
- case endpoint of
- Core.CEq Core.TySet (Core.CBound left) (Core.CBound right) ->
- assertBool "quantified endpoint keeps asymmetric binders"
- (left /= right)
- _ ->
- assertFailure
- ("unexpected quantified endpoint: " <> show endpoint)
- target ->
- assertFailure
- ("expected quantified guarded implication, found "
- <> show target)
-
- quantifiedCalculationShape proposition =
- case dropForalls 2 proposition of
- Core.CImp constraint endpoint ->
- Just
- ( countIntrinsic Core.Member constraint
- , countSetEqualities constraint
- , endpoint
- )
- _ -> Nothing
-
- dropForalls
- :: Int
- -> Core.CanonicalTerm Identity.ObjectId
- -> Core.CanonicalTerm Identity.ObjectId
- dropForalls 0 term = term
- dropForalls remaining (Core.CForall _binder body) =
- dropForalls (remaining - 1) body
- dropForalls _remaining term = term
-
- countIntrinsic
- :: Core.CoreIntrinsicTag
- -> Core.CanonicalTerm Identity.ObjectId
- -> Int
- countIntrinsic intrinsic = \case
- Core.CBound{} -> 0
- Core.CGlobal{} -> 0
- Core.CIntrinsic found -> fromEnum (found == intrinsic)
- Core.COpaqueInteger{} -> 0
- Core.CApp function argument ->
- countIntrinsic intrinsic function
- + countIntrinsic intrinsic argument
- Core.CLam _binder body -> countIntrinsic intrinsic body
- Core.CFalsum -> 0
- Core.CImp premise conclusion ->
- countIntrinsic intrinsic premise
- + countIntrinsic intrinsic conclusion
- Core.CEq _operand left right ->
- countIntrinsic intrinsic left
- + countIntrinsic intrinsic right
- Core.CForall _binder body -> countIntrinsic intrinsic body
-
- countSetEqualities
- :: Core.CanonicalTerm Identity.ObjectId
- -> Int
- countSetEqualities = \case
- Core.CBound{} -> 0
- Core.CGlobal{} -> 0
- Core.CIntrinsic{} -> 0
- Core.COpaqueInteger{} -> 0
- Core.CApp function argument ->
- countSetEqualities function + countSetEqualities argument
- Core.CLam _binder body -> countSetEqualities body
- Core.CFalsum -> 0
- Core.CImp premise conclusion ->
- countSetEqualities premise + countSetEqualities conclusion
- Core.CEq operand left right ->
- fromEnum (operand == Core.TySet)
- + countSetEqualities left
- + countSetEqualities right
- Core.CForall _binder body -> countSetEqualities body
-
- equalityOperandType = \case
- Core.CEq operandType _left _right -> operandType
- term -> error ("expected checked equality, found " <> show term)
-
- leadingForalls
- :: Core.CanonicalTerm Identity.ObjectId
- -> Int
- leadingForalls = \case
- Core.CForall _binder body -> 1 + leadingForalls body
- _ -> 0
-
- assertRejectedPrefix
- label foundation bootstrap workspace executable rejectedIndex
- expectedPrefix expectedRuns = do
- runs <- newIORef (0 :: Int)
- parsed <- sole (label <> " parsed module")
- (toList (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- let resolver =
- Declaration.vampireResolver \prepared -> do
- index <- atomicModifyIORef' runs \current ->
- (current + 1, current)
- if index == rejectedIndex
- then pure
- (Right
- (Provers.CounterSatisfiable
- "focused deterministic rejection"))
- else
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- resolver
- Declaration.FreshValidation
- parsed
- [])
- Module.runTypedModule input >>= \case
- Module.TypedModuleFailed _failure prefix ->
- assertEqual
- (label <> " publishes only the prior prefix")
- expectedPrefix
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Module.TypedModuleSucceeded{} ->
- assertFailure (label <> " unexpectedly succeeded")
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- (label <> " did not open: " <> show failure)
- assertEqual (label <> " selects the first rejected request")
- expectedRuns =<< readIORef runs
-
-data LocalReasoningObservation = LocalReasoningObservation
- { localReasoningTarget :: !(Core.CanonicalTerm Identity.ObjectId)
- , localReasoningGlobalCount :: !Int
- , localReasoningLocalOrdinals :: ![Natural]
- , localReasoningLocalTerms ::
- ![Core.CanonicalTerm Identity.ObjectId]
- , localReasoningAuxiliaries :: ![Foundation.FoundationAxiomTag]
- }
- deriving (Show)
-
-selectsCalculationLinkFailureBySourceOrder :: Assertion
-selectsCalculationLinkFailureBySourceOrder = do
- foundation <- expectRight Foundation.checkedFoundation
- Temp.withSystemTempDirectory "felix-calculation-link-order" \root -> do
- let executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- source = "test/phase7/calculation-link-order.tex"
- laterCompleted = root Posix.</> "later-completed"
- firstRun = root Posix.</> "first-run"
- secondRun = root Posix.</> "second-run"
- prover =
- Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit
- writeAcceptedFixtureVampire executable
- (_startup, store) <-
- Store.openStore storePath (Identity.theoryId foundation)
- >>= expectRight
- bracket (pure store) Store.closeStore \openStore -> do
- let ignored =
- Verification.verificationRequestObserver
- (\_position _request -> pure ())
- void
- (
- (checkFileWithStore
- openStore
- Verification.WarmStoreValidation
- ignored
- prover
- "test/phase3/typed-unsupported.tex")
- >>= expectRight)
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "if mkdir \"" <> firstRun <> "\" 2>/dev/null; then"
- , " printf '%s\\n' '% SZS status Theorem for calculation-link-order'"
- , "elif mkdir \"" <> secondRun <> "\" 2>/dev/null; then"
- , " : > \"" <> laterCompleted <> "\""
- , " printf '%s\\n' '% SZS status Theorem for calculation-link-order'"
- , "else"
- , " printf '%s\\n' '% SZS status CounterSatisfiable for calculation-link-order'"
- , "fi"
- ])
- permissions <- getPermissions executable
- setPermissions executable (setOwnerExecutable True permissions)
- jobs <-
- Provers.selectEffectiveJobs
- (Provers.effectiveJobs 2)
- (fail "explicit jobs unexpectedly detected processors")
- positions <- newIORef []
- middleStarted <- newEmptyTMVarIO
- laterStarted <- newEmptyTMVarIO
- releaseMiddle <- newEmptyTMVarIO
- let observer =
- Verification.verificationRequestObserver \position _request -> do
- let ordinal =
- Provers.workPositionLocalRequestOrdinal position
- modifyIORef' positions (position :)
- case ordinal of
- 1 -> pure ()
- 2 -> do
- atomically (putTMVar middleStarted ())
- atomically (takeTMVar releaseMiddle)
- 3 -> atomically (putTMVar laterStarted ())
- _ ->
- assertFailure
- ("unexpected calculation request ordinal: "
- <> show ordinal)
- withAsync
- (
- (checkFileWithStoreAndJobs
- openStore
- Verification.WarmStoreValidation
- jobs
- observer
- prover
- source)
- >>= expectRight)
- \verification -> do
- void
- (awaitTmvar "middle calculation link" middleStarted)
- void
- (awaitTmvar "later calculation continuation" laterStarted)
- waitForFileSignal
- "later calculation continuation" laterCompleted
- atomically (putTMVar releaseMiddle ())
- (result, _slowReport) <- wait verification
- case result of
- Verification.VerificationFailure report failed -> do
- assertEqual "middle link failure location"
- (source, 10)
- ( locFile
- (Verification.failedVerificationLocation failed)
- , locLine
- (Verification.failedVerificationLocation failed)
- )
- assertEqual "failed calculation admits no source fact"
- [] (Verification.verificationDirectEscapes report)
- other ->
- assertFailure
- ("calculation link order did not reject: "
- <> show other)
- observedPositions <-
- fmap
- (\position ->
- ( Provers.workPositionModuleOrdinal position
- , Provers.workPositionLocalRequestOrdinal
- position
- ))
- <$> readIORef positions
- assertEqual "all calculation requests executed"
- [(1, 1), (1, 2), (1, 3)]
- (sort observedPositions)
-
- writeAcceptedFixtureVampire executable
- retryPositions <- newIORef []
- let retryObserver =
- Verification.verificationRequestObserver \position _request ->
- modifyIORef' retryPositions (position :)
- (retry, _retrySlowReport) <-
- (checkFileWithStoreAndJobs
- openStore
- Verification.WarmStoreValidation
- jobs
- retryObserver
- prover
- source)
- >>= expectRight
- case retry of
- Verification.VerificationCompleted{} -> pure ()
- other ->
- assertFailure
- ("calculation rollback retry failed: " <> show other)
- retryObserved <- readIORef retryPositions
- assertEqual "retry executes the complete calculation proof"
- 3 (length retryObserved)
- where
- awaitTmvar label variable = do
- result <- Timeout.timeout 10000000
- (atomically (takeTMVar variable))
- maybe
- (assertFailure (label <> " was not observed")
- >> fail "unreachable")
- pure
- result
-
-assertProofParityFailure
- :: Foundation.CheckedFoundation
- -> Module.BootstrapPreludeFixture
- -> SourceMounts
- -> FilePath
- -> (ExactProof.ExactProofError -> Bool)
- -> Assertion
-assertProofParityFailure foundation bootstrap mounts relative matches = do
- workspace <- parseExactWorkspace bootstrap mounts relative
- parsed <- sole "invalid proof-parity module"
- (toList (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- unusedResolver
- Declaration.FreshValidation
- parsed
- [])
- Module.runTypedModule input >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactProofFailed failure))
- prefix -> do
- assertBool ("unexpected proof failure: " <> show failure)
- (matches failure)
- assertBool "failing proof publishes no declaration"
- (null (Declaration.pendingModulePrefixBatches prefix))
- Module.TypedModuleSucceeded{} ->
- assertFailure "invalid proof-parity module succeeded"
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("invalid proof-parity module did not open: " <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("unexpected proof-parity module failure: " <> show failure)
-
-compilesExactSeparationComprehensions :: Assertion
-compilesExactSeparationComprehensions =
- Temp.withSystemTempDirectory "felix-exact-separation" \root -> do
- let relative = "test/phase5/exact-separation.tex"
- executable = root Posix.</> "vampire"
- failedSource = root Posix.</> relative
- repository <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace bootstrap mounts relative
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for exact-separation'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- observations <- newIORef []
- let resolver = Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- request =
- Provers.preparedTypedProverRequest prepared
- globals =
- Backend.typedProblemGlobalPremises problem
- modifyIORef' observations
- (<> [ ( Backend.typedProblemRoute problem
- , Backend.typedBackendFactReference <$> globals
- , all
- (\fact ->
- case Backend.typedBackendFactCapability fact of
- Backend.FofProjectable{} -> True
- Backend.RequiresTh0{} -> False)
- globals
- , Backend.localPremiseOrdinalValue
- . Backend.typedLocalPremiseOrdinal
- <$> Vector.toList
- (Backend.typedProblemLocalPremises problem)
- , Backend.typedProblemAuxiliaryTag
- <$> Vector.toList
- (Backend.typedProblemAuxiliaries problem)
- , Provers.preparedVerificationRequestId request
- , Provers.preparedVerificationByteCount request
- )
- ])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- modules <- compileParsedWorkspaceWithResolver
- foundation bootstrap resolver workspace
- sealed <- sole "exact separation module" modules
- assertExactSeparationModule "fresh" sealed
- definition <- batchByAlias
- (Module.sealedTypedModulePrefix sealed)
- "phase5_separation_definition"
- let definitionFacts =
- Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta definition)
- extensional <- sole "searchable separation view"
- [ Semantic.semanticFactFingerprint occurrence
- | occurrence <- definitionFacts
- , Semantic.semanticFactSearchEligibility occurrence
- == Semantic.SearchEligible
- ]
- equation <- sole "explicit separation equation"
- [ Semantic.semanticFactFingerprint occurrence
- | occurrence <- definitionFacts
- , Semantic.semanticFactSearchEligibility occurrence
- == Semantic.SearchIneligible
- ]
- readIORef observations >>= \case
- [ ( Backend.RouteFof
- , selectedGlobals
- , True
- , [0]
- , []
- , _requestId
- , requestBytes
- ) ] -> do
- assertBool "searchable separation view is selected"
- (extensional `elem` selectedGlobals)
- assertBool "exact separation equation is not selected"
- (equation `notElem` selectedGlobals)
- assertBool "separation exact request has bytes"
- (requestBytes > 0)
- observed ->
- assertFailure
- ("unexpected implicit separation problem: "
- <> show observed)
-
- createDirectoryIfMissing True (Posix.takeDirectory failedSource)
- original <- ByteString.readFile relative
- let invalid =
- Text.encodeUtf8
- (StrictText.replace
- "x \\in A \\mid x = x"
- "x \\in x \\mid x = x"
- (Text.decodeUtf8 original))
- ByteString.writeFile failedSource invalid
- failedMounts <- exactFixtureMounts root
- failedWorkspace <-
- parseExactWorkspace bootstrap failedMounts relative
- let parsed = Parse.parsedWorkspaceRootModule failedWorkspace
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- unusedResolver
- Declaration.FreshValidation
- parsed
- [])
- Module.runTypedModule input >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactCompileFailed
- (Exact.ExactFreeVariable location
- (Raw.NamedVar "x"))))
- prefix -> do
- assertEqual "invalid separation bound line"
- 2 (locLine location)
- assertEqual
- "invalid separation publishes none of its declaration"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Module.TypedModuleSucceeded{} ->
- assertFailure "invalid separation was accepted"
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("invalid separation module did not open: "
- <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("unexpected invalid separation failure: "
- <> show failure)
-
-compilesAndReusesProofLocalSetDefinitions :: Assertion
-compilesAndReusesProofLocalSetDefinitions =
- Temp.withSystemTempDirectory "felix-exact-local-definition" \root -> do
- let relative = "test/phase5/exact-local-definition.tex"
- failedRelative =
- "test/phase5/exact-local-definition-failure.tex"
- sourcePath = root Posix.</> relative
- failedSourcePath = root Posix.</> failedRelative
- executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- createDirectoryIfMissing True (Posix.takeDirectory sourcePath)
- ByteString.readFile relative >>= ByteString.writeFile sourcePath
- createDirectoryIfMissing True (Posix.takeDirectory failedSourcePath)
- ByteString.readFile failedRelative
- >>= ByteString.writeFile failedSourcePath
- writeAcceptedFixtureVampire executable
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts root
- workspace <- parseExactWorkspace bootstrap mounts relative
- freshRuns <- newIORef (0 :: Int)
- observations <- newIORef []
- let freshResolver = Declaration.vampireResolver \prepared -> do
- modifyIORef' freshRuns (+ 1)
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- premises =
- Backend.typedProblemLocalPremises problem
- definition =
- Vector.find
- ((== Backend.localPremiseOrdinal 0)
- . Backend.typedLocalPremiseOrdinal)
- premises
- modifyIORef' observations
- (<> [ ( Backend.typedProblemRoute problem
- , Backend.localPremiseOrdinalValue
- . Backend.typedLocalPremiseOrdinal
- <$> Vector.toList premises
- , fmap localDefinitionShape definition
- )
- ])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- freshModules <-
- compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- freshResolver
- Declaration.FreshValidation
- workspace
- assertEqual "fresh local-definition discharge count"
- 2 =<< readIORef freshRuns
- assertEqual "implicit and local-only definition views"
- [ (Backend.RouteFof, [0, 2], Just expectedLocalDefinitionShape)
- , (Backend.RouteTh0, [0, 1, 3], Just expectedLocalDefinitionShape)
- ]
- =<< readIORef observations
- fresh <- sole "fresh local-definition module" freshModules
- localDefinitionBatch <- sole
- "proof-local definition publishes one declaration"
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix fresh))
- assertEqual "proof-local definition publishes no object"
- []
- (Declaration.committedBatchObjects localDefinitionBatch)
- assertEqual "proof-local definition publishes only its theorem"
- 1
- (length
- (Declaration.committedBatchPropositions
- localDefinitionBatch))
- localDefinitionFact <- sole
- "proof-local definition theorem"
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta
- localDefinitionBatch))
- assertEqual "proof-local definition remains clean"
- Authority.cleanAuthoritySafety
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority localDefinitionFact))
-
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmRuns <- newIORef (0 :: Int)
- warmModules <-
- compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- (countingAcceptedResolver executable warmRuns)
- validation
- workspace
- assertEqual "warm local-definition proof skips Vampire"
- 0 =<< readIORef warmRuns
- warm <- sole "warm local-definition module" warmModules
- assertEqual "warm local-definition semantic interface"
- (Module.sealedTypedModuleSemantic fresh)
- (Module.sealedTypedModuleSemantic warm)
- assertEqual "warm local-definition prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix fresh))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warm))
-
- failedWorkspace <-
- parseExactWorkspace bootstrap mounts failedRelative
- let failedParsed =
- Parse.parsedWorkspaceRootModule failedWorkspace
- failedInput <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- unusedResolver
- Declaration.FreshValidation
- failedParsed
- [])
- Module.runTypedModule failedInput >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactProofFailed
- (ExactProof.ExactProofElaborationFailed
- (Exact.ExactFreeVariable location
- (Raw.NamedVar "B")))))
- prefix -> do
- assertEqual "self-reference rejection line"
- 6 (locLine location)
- assertBool "failed local definition publishes no theorem"
- (null
- (Declaration.pendingModulePrefixBatches prefix))
- Module.TypedModuleSucceeded{} ->
- assertFailure "self-referential local definition was accepted"
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("local-definition failure fixture did not open: "
- <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("unexpected local-definition failure: "
- <> show failure)
- where
- localDefinitionShape premise =
- let proposition =
- Backend.typedLocalPremiseProposition premise
- in ( fmap
- snd
- (Vector.toList
- (Backend.supportedPropositionSupport proposition))
- , Backend.supportedPropositionTerm proposition
- )
-
- expectedLocalDefinitionShape =
- ( [Core.TySet, Core.TySet]
- , Core.CForall Core.TySet
- (Core.CEq Core.TyProp
- (member (Core.CBound 0) (Core.CBound 1))
- (andP
- (member (Core.CBound 0) (Core.CBound 2))
- (Core.CEq Core.TySet
- (Core.CBound 0)
- (Core.CBound 0))))
- )
-
- member element set =
- Core.CApp
- (Core.CApp
- (Core.CIntrinsic Core.Member)
- element)
- set
-
- andP left right =
- Core.CImp
- (Core.CImp left (Core.CImp right Core.CFalsum))
- Core.CFalsum
-
-compilesAndReusesProofLocalFunctionGraphs :: Assertion
-compilesAndReusesProofLocalFunctionGraphs =
- Temp.withSystemTempDirectory "felix-exact-local-function" \root -> do
- let relative = "test/phase5/exact-local-function.tex"
- failedRelative =
- "test/phase5/exact-local-function-failure.tex"
- executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- writeAcceptedFixtureVampire executable
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- mounts <- exactFixtureMounts =<< getCurrentDirectory
- workspace <- parseExactWorkspace bootstrap mounts relative
- observations <- newIORef []
- let resolver = Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- premises =
- [ ( Backend.typedProblemRoute problem
- , fmap snd
- (Vector.toList
- (Backend.supportedPropositionSupport
- proposition))
- , Backend.supportedPropositionTerm proposition
- )
- | premise <-
- Vector.toList
- (Backend.typedProblemLocalPremises problem)
- , let proposition =
- Backend.typedLocalPremiseProposition premise
- ]
- modifyIORef' observations (<> premises)
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- freshModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap resolver
- Declaration.FreshValidation workspace
- allObserved <- readIORef observations
- let observed =
- [ (route, proposition)
- | (route, support, proposition) <- allObserved
- , support == [Core.TySet, Core.TySet]
- , isJust (localFunctionPair proposition)
- ]
- assertBool
- ("the local graph characteristic reaches a discharge: "
- <> show allObserved)
- (not (null observed))
- for_ observed \(route, proposition) -> do
- assertEqual "local function characteristic stays on FOF"
- Backend.RouteFof route
- assertExactLocalFunctionCharacteristic proposition
- freshRoot <- sole "fresh local-function root"
- (take 1 (reverse freshModules))
- rootBatch <- sole "local function publishes only its theorem"
- (drop 1
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix freshRoot)))
- assertEqual "local function publishes no object"
- [] (Declaration.committedBatchObjects rootBatch)
- assertEqual "local function publishes only its theorem"
- 1
- (length
- (Declaration.committedBatchPropositions rootBatch))
- assertEqual "local function publishes no semantic binding"
- []
- (Semantic.semanticEnvironmentBindings
- (Semantic.declarationDeltaEnvironment
- (Declaration.committedBatchDelta rootBatch)))
- rootFact <- sole "local-function theorem"
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta rootBatch))
- assertEqual "local-function theorem remains clean"
- Authority.cleanAuthoritySafety
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority rootFact))
-
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- traverse_
- (expectRightIO
- . Store.writePendingModulePrefix store
- . Module.sealedTypedModulePrefix)
- freshModules
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmRuns <- newIORef (0 :: Int)
- warmModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap
- (countingAcceptedResolver executable warmRuns)
- validation workspace
- assertEqual "warm local-function graph skips Vampire"
- 0 =<< readIORef warmRuns
- warmRoot <- sole "warm local-function root"
- (take 1 (reverse warmModules))
- assertEqual "warm local-function semantic interface"
- (Module.sealedTypedModuleSemantic freshRoot)
- (Module.sealedTypedModuleSemantic warmRoot)
- assertEqual "warm local-function prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix freshRoot))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warmRoot))
-
- failedWorkspace <-
- parseExactWorkspace bootstrap mounts failedRelative
- failedInput <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- unusedResolver
- Declaration.FreshValidation
- (Parse.parsedWorkspaceRootModule failedWorkspace)
- [])
- Module.runTypedModule failedInput >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactProofFailed
- (ExactProof.ExactProofElaborationFailed
- (Exact.ExactFreeVariable location
- (Raw.NamedVar "f")))))
- prefix -> do
- assertEqual "self-reference rejection line"
- 6 (locLine location)
- assertBool "failed local function publishes no theorem"
- (null
- (Declaration.pendingModulePrefixBatches prefix))
- Module.TypedModuleSucceeded{} ->
- assertFailure "self-referential local function was accepted"
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("local-function failure fixture did not open: "
- <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("unexpected local-function failure: "
- <> show failure)
- where
- assertExactLocalFunctionCharacteristic proposition = do
- pair <-
- maybe
- (assertFailure "local function characteristic has wrong shape")
- pure
- (localFunctionPair proposition)
- assertEqual "local function uses the exact replacement characteristic"
- (expectedLocalFunctionCharacteristic pair)
- proposition
-
- localFunctionPair proposition =
- case Set.toList (Core.canonicalTermGlobals proposition) of
- [pair]
- | proposition == expectedLocalFunctionCharacteristic pair ->
- Just pair
- _ ->
- Nothing
-
- expectedLocalFunctionCharacteristic pair =
- Core.CForall Core.TySet
- (Core.CEq Core.TyProp
- (member (Core.CBound 0) (Core.CBound 1))
- (existsP
- (andP
- (member (Core.CBound 0) (Core.CBound 3))
- (Core.CEq Core.TySet
- (Core.CBound 1)
- (Core.CApp
- (Core.CApp
- (Core.CGlobal pair)
- (Core.CBound 0))
- (Core.CBound 0))))))
-
- member element set =
- Core.CApp
- (Core.CApp (Core.CIntrinsic Core.Member) element)
- set
-
- andP left right =
- notP (Core.CImp left (notP right))
-
- existsP proposition =
- notP (Core.CForall Core.TySet (notP proposition))
-
- notP proposition =
- Core.CImp proposition Core.CFalsum
-
-confinesTerminalExactContradiction :: Assertion
-confinesTerminalExactContradiction =
- Temp.withSystemTempDirectory "felix-exact-contradiction" \directory -> do
- let acceptedExecutable = directory Posix.</> "accepted-vampire"
- contradictoryExecutable = directory Posix.</> "contradictory-vampire"
- storePath = directory Posix.</> "store.sqlite"
- writeAcceptedFixtureVampire acceptedExecutable
- writeFile contradictoryExecutable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status ContradictoryAxioms for exact-contradiction'"
- ])
- permissions <- getPermissions contradictoryExecutable
- setPermissions contradictoryExecutable
- (setOwnerExecutable True permissions)
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- mounts <- exactFixtureMounts =<< getCurrentDirectory
- workspace <- parseExactWorkspace bootstrap mounts
- "test/phase5/exact-cases-contradiction.tex"
- assertEmptyCaseAstRejected foundation bootstrap workspace
- observations <- newIORef []
- fresh <-
- sole "cases and contradiction module"
- =<< compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- (observingResolver
- acceptedExecutable
- contradictoryExecutable
- observations)
- Declaration.FreshValidation
- workspace
- observed <- readIORef observations
- assertEqual "cases and contradiction request count"
- 8 (length observed)
- case observed of
- branchOne : branchTwo : branchThree : exhaustive
- : byContradiction : arbitraryContradiction
- : omittedLaterBranch : omittedExhaustive : [] -> do
- assertEqual "case branches have isolated local ordinals"
- [[0], [1], [2]]
- (localReasoningLocalOrdinals
- <$> [branchOne, branchTwo, branchThree])
- assertEqual "exhaustiveness sees pre-case locals only"
- [] (localReasoningLocalOrdinals exhaustive)
- case
- ( localReasoningLocalTerms branchOne
- , localReasoningLocalTerms branchTwo
- , localReasoningLocalTerms branchThree
- ) of
- ([caseOne], [caseTwo], [caseThree]) ->
- assertEqual
- "case exhaustiveness is left-associated in source order"
- (orP (orP caseOne caseTwo) caseThree)
- (localReasoningTarget exhaustive)
- branchTerms ->
- assertFailure
- ("unexpected branch-local premises: "
- <> show branchTerms)
- assertEqual "proof by contradiction targets falsum"
- Core.CFalsum
- (localReasoningTarget byContradiction)
- assertBool
- "double-negation elimination is not an ATP auxiliary"
- (Foundation.DoubleNegationElim
- `notElem` localReasoningAuxiliaries byContradiction)
- case localReasoningLocalTerms byContradiction of
- [Core.CImp negatedGoal Core.CFalsum] ->
- assertEqual
- "proof by contradiction assumes the exact negated goal"
- (localReasoningTarget branchOne)
- negatedGoal
- locals ->
- assertFailure
- ("unexpected contradiction locals: "
- <> show locals)
- assertEqual "arbitrary terminal contradiction targets falsum"
- Core.CFalsum
- (localReasoningTarget arbitraryContradiction)
- assertEqual "omitted case does not leak into its sibling"
- [1]
- (localReasoningLocalOrdinals omittedLaterBranch)
- assertEqual "omitted exhaustiveness sees no branch local"
- [] (localReasoningLocalOrdinals omittedExhaustive)
- _ ->
- assertFailure
- ("unexpected cases/contradiction observations: "
- <> show observed)
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix fresh) of
- [caseBatch, byContradictionBatch, terminalBatch, omittedBatch] -> do
- traverse_
- (assertBatchSafety Authority.cleanAuthoritySafety)
- [caseBatch, byContradictionBatch, terminalBatch]
- assertBatchSafety
- (Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.Omitted))
- omittedBatch
- batches ->
- assertFailure
- ("unexpected cases/contradiction declaration count: "
- <> show (length batches))
-
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmRuns <- newIORef (0 :: Int)
- warm <-
- sole "warm cases and contradiction module"
- =<< compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- (countingAcceptedResolver
- acceptedExecutable warmRuns)
- validation
- workspace
- assertEqual "warm structural proofs skip Vampire"
- 0 =<< readIORef warmRuns
- assertEqual "fresh and warm structural proof validations"
- (proofValidations fresh)
- (proofValidations warm)
-
- failureWorkspace <- parseExactWorkspace bootstrap mounts
- "test/phase5/exact-case-failure.tex"
- assertCaseFailure
- "middle case branch"
- foundation bootstrap failureWorkspace acceptedExecutable 1 2
- assertCaseFailure
- "case exhaustiveness"
- foundation bootstrap failureWorkspace acceptedExecutable 3 4
-
- directWorkspace <- parseExactWorkspace bootstrap mounts
- "test/phase5/exact-direct-contradictory.tex"
- directParsed <- sole "direct contradictory parsed module"
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter directWorkspace))
- directInput <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- (Declaration.vampireResolver
- (runWith contradictoryExecutable))
- Declaration.FreshValidation
- directParsed
- [])
- Module.runTypedModule directInput >>= \case
- Module.TypedModuleFailed
- (Module.TypedDeclarationFailed
- (Declaration.ProofObligationFailedAt
- _location
- Declaration.VampireObligationRejected{}))
- prefix ->
- assertBool
- "direct contradictory input publishes no theorem"
- (null (Declaration.pendingModulePrefixBatches prefix))
- _result ->
- assertFailure "direct contradictory input was accepted"
- where
- observingResolver acceptedExecutable contradictoryExecutable observations =
- Declaration.vampireResolver \prepared -> do
- let problem = Provers.preparedTypedProverLogicalProblem prepared
- claim = Backend.typedProblemClaim problem
- locals = Backend.typedProblemLocalPremises problem
- target = Backend.supportedPropositionTerm claim
- modifyIORef' observations
- (<> [ LocalReasoningObservation
- { localReasoningTarget = target
- , localReasoningGlobalCount =
- Vector.length
- (Backend.typedProblemGlobalPremises problem)
- , localReasoningLocalOrdinals =
- [ Backend.localPremiseOrdinalValue
- (Backend.typedLocalPremiseOrdinal premise)
- | premise <- Vector.toList locals
- ]
- , localReasoningLocalTerms =
- Backend.supportedPropositionTerm
- . Backend.typedLocalPremiseProposition
- <$> Vector.toList locals
- , localReasoningAuxiliaries =
- Backend.typedProblemAuxiliaryTag
- <$> Vector.toList
- (Backend.typedProblemAuxiliaries problem)
- }
- ])
- runWith
- (if target == Core.CFalsum
- then contradictoryExecutable
- else acceptedExecutable)
- prepared
-
- runWith executable prepared =
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
-
- assertEmptyCaseAstRejected foundation bootstrap workspace = do
- parsed <- sole "cases parsed module"
- (toList (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- let blocks =
- Parse.identifiedParsedModuleBlocks
- (Parse.parsedModuleIdentified parsed)
- claim <- sole "cases source claim"
- [ candidate
- | candidate@Raw.BlockClaim{} <- take 1 blocks
- ]
- location <-
- case
- [ found
- | Raw.BlockProof _ (Raw.ByCase found _cases) _ <- blocks
- ] of
- found : _ -> pure found
- [] ->
- assertFailure "cases source proof is absent"
- >> fail "unreachable"
- let preludeModule = Module.bootstrapPreludeModule bootstrap
- outcome <- Declaration.runModuleDriver
- foundation
- (moduleName (Parse.parsedModuleAddress parsed))
- [ Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic preludeModule)
- ]
- unusedResolver
- Declaration.FreshValidation do
- Declaration.importSealedModuleDriver
- (Module.sealedTypedModuleEvidence preludeModule)
- Declaration.runProspectiveLoweringDriver
- (ExactProof.prepareExactProof
- claim
- (Just (Raw.ByCase location [])))
- case outcome of
- Right (Declaration.DriverSucceeded
- (Left (ExactProof.ExactProofEmptyCaseSplit found))
- _semantic prefix _closure) -> do
- assertEqual "empty case AST failure location"
- location found
- assertBool "empty case AST publishes no declaration"
- (null (Declaration.pendingModulePrefixBatches prefix))
- _ ->
- assertFailure "empty programmatic case split was not rejected"
-
- assertBatchSafety expected batch = do
- fact <- sole "structural proof fact"
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch))
- assertEqual "structural proof authority safety"
- expected
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority fact))
-
- proofValidations =
- concatMap Declaration.committedBatchProofValidations
- . Declaration.pendingModulePrefixBatches
- . Module.sealedTypedModulePrefix
-
- assertCaseFailure
- label foundation bootstrap workspace executable rejectedIndex
- expectedRuns = do
- runs <- newIORef (0 :: Int)
- parsed <- sole (label <> " parsed module")
- (toList (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- let resolver =
- Declaration.vampireResolver \prepared -> do
- index <- atomicModifyIORef' runs \current ->
- (current + 1, current)
- if index == rejectedIndex
- then pure
- (Right
- (Provers.CounterSatisfiable
- "focused case rejection"))
- else runWith executable prepared
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- resolver
- Declaration.FreshValidation
- parsed
- [])
- Module.runTypedModule input >>= \case
- Module.TypedModuleFailed _failure prefix ->
- assertBool
- (label <> " publishes no declaration")
- (null (Declaration.pendingModulePrefixBatches prefix))
- _result ->
- assertFailure (label <> " unexpectedly succeeded")
- assertEqual
- (label <> " selects failures in source order")
- expectedRuns =<< readIORef runs
-
- orP left right = Core.CImp (Core.CImp left Core.CFalsum) right
-
-compilesExactReplacementComprehensions :: Assertion
-compilesExactReplacementComprehensions =
- Temp.withSystemTempDirectory "felix-exact-replacement" \root -> do
- let relative = "test/phase5/exact-replacement.tex"
- executable = root Posix.</> "vampire"
- repository <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace bootstrap mounts relative
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for exact-replacement'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- observations <- newIORef []
- let resolver = Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- modifyIORef' observations
- (<> [ ( Backend.typedProblemRoute problem
- , Backend.typedProblemAuxiliaryTag
- <$> Vector.toList
- (Backend.typedProblemAuxiliaries problem)
- )
- ])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- modules <- compileParsedWorkspaceWithResolver
- foundation bootstrap resolver workspace
- sealed <- sole "exact replacement module" modules
- assertExactReplacementModule sealed
- assertEqual
- "replacement proof uses its checked characteristic on TH0"
- [( Backend.RouteTh0
- , [Foundation.ReplacementCharacteristic]
- )]
- =<< readIORef observations
-
-assertExactReplacementModule
- :: Module.SealedTypedModule
- -> Assertion
-assertExactReplacementModule sealed =
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed) of
- [definitionBatch, theoremBatch] -> do
- definitionObject <- sole
- "replacement definition object"
- (Declaration.committedBatchObjects definitionBatch)
- case Identity.assertedObjectContent definitionObject of
- Identity.TransparentObjectContent
- _theory coreType body -> do
- assertEqual "replacement definition type"
- (Core.TyArrow Core.TySet Core.TySet)
- coreType
- assertEqual "replacement definition body"
- expectedBody
- body
- assertEqual "replacement definition foundation helpers"
- (Set.fromList
- [ Foundation.FamilyUnionCharacteristic
- , Foundation.SeparationCharacteristic
- , Foundation.ReplacementCharacteristic
- ])
- (Foundation.foundationAxiomDependencies body)
- content ->
- assertFailure
- ("unexpected replacement object " <> show content)
- let definitionDelta =
- Declaration.committedBatchDelta definitionBatch
- definitionFacts =
- Semantic.declarationDeltaFacts definitionDelta
- assertEqual "replacement definition fact count"
- 2 (length definitionFacts)
- assertEqual "replacement equation/search view eligibility"
- [Semantic.SearchIneligible, Semantic.SearchEligible]
- (Semantic.semanticFactSearchEligibility <$> definitionFacts)
- assertEqual "replacement generated view is unaliased"
- 1
- (length (Semantic.declarationDeltaAliases definitionDelta))
- assertEqual "replacement definition proposition count"
- 2
- (length
- (Declaration.committedBatchPropositions definitionBatch))
- assertEqual "replacement definition proof validations"
- []
- (Declaration.committedBatchProofValidations definitionBatch)
- definitionValidation <-
- maybe
- (assertFailure "replacement validation is absent"
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation
- definitionBatch)
- case Authority.validationDirectAuthorization
- <$> Semantic.declarationValidationRecordCertificates
- definitionValidation of
- [ Authority.CheckedKernelConstruction
- (Authority.CheckedDefinitionEquation target)
- , Authority.CheckedKernelConstruction
- (Authority.CheckedSetConstructionExtensionality
- generatedTarget _descriptor)
- ] ->
- assertEqual "replacement construction authority object"
- target generatedTarget
- authorizations ->
- assertFailure
- ("unexpected replacement definition authorities "
- <> show authorizations)
-
- assertEqual "replacement theorem adds no object"
- []
- (Declaration.committedBatchObjects theoremBatch)
- assertEqual "replacement theorem fact count"
- 1
- (length
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta theoremBatch)))
- assertEqual "replacement theorem proposition count"
- 1
- (length
- (Declaration.committedBatchPropositions theoremBatch))
- theoremValidation <- sole
- "replacement theorem validation"
- (Declaration.committedBatchProofValidations theoremBatch)
- case Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate
- theoremValidation) of
- Authority.CheckedSourceProof [_request] ->
- pure ()
- authorization ->
- assertFailure
- ("unexpected replacement theorem authority "
- <> show authorization)
- batches ->
- assertFailure
- ("expected replacement definition and theorem, found "
- <> show (length batches))
- where
- app1 intrinsic argument =
- Core.CApp (Core.CIntrinsic intrinsic) argument
- app2 intrinsic first second =
- Core.CApp (app1 intrinsic first) second
- expectedBody =
- Core.CLam Core.TySet $
- app1 Core.FamilyUnion $
- app2 Core.Repl (Core.CBound 0) $
- Core.CLam Core.TySet $
- app2 Core.Repl
- (app2 Core.Sep
- (Core.CBound 0)
- (Core.CLam Core.TySet $
- Core.CEq Core.TySet
- (Core.CBound 1)
- (Core.CBound 0)))
- (Core.CLam Core.TySet
- (Core.CBound 0))
-
-compilesAndReusesRelationalReplacement :: Assertion
-compilesAndReusesRelationalReplacement =
- Temp.withSystemTempDirectory "felix-exact-relational-replacement" \root -> do
- let relative = "test/phase5/exact-relational-replacement.tex"
- failureRelative =
- "test/phase5/exact-relational-replacement-failure.tex"
- localFailureRelative =
- "test/phase5/exact-relational-replacement-local-failure.tex"
- executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- writeAcceptedFixtureVampire executable
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- mounts <- exactFixtureMounts =<< getCurrentDirectory
- workspace <- parseExactWorkspace bootstrap mounts relative
- observed <- newIORef []
- runs <- newIORef (0 :: Int)
- let resolver = Declaration.vampireResolver \prepared -> do
- modifyIORef' runs (+ 1)
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- modifyIORef' observed
- (<> [ ( Backend.typedProblemRoute problem
- , Backend.localPremiseOrdinalValue
- . Backend.typedLocalPremiseOrdinal
- <$> Vector.toList
- (Backend.typedProblemLocalPremises problem)
- , Backend.typedProblemAuxiliaryTag
- <$> Vector.toList
- (Backend.typedProblemAuxiliaries problem)
- )
- ])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- freshModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap resolver
- Declaration.FreshValidation workspace
- fresh <- sole "fresh relational replacement module" freshModules
- assertRelationalReplacementModule fresh
- problems <- readIORef observed
- assertEqual "relational replacement request count"
- 3 (length problems)
- firstProblem <- sole "module functionality request" (take 1 problems)
- assertEqual "module functionality uses FOF"
- Backend.RouteFof
- (case firstProblem of (route, _, _) -> route)
- assertEqual "module functionality has no local premises"
- []
- (case firstProblem of (_, ordinals, _) -> ordinals)
- assertEqual
- "relational equivalence creates no ATP obligation or auxiliary"
- [ (Backend.RouteFof, [], [])
- , (Backend.RouteFof, [], [])
- , (Backend.RouteFof, [0], [])
- ]
- problems
-
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmRuns <- newIORef (0 :: Int)
- warmModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap
- (countingAcceptedResolver executable warmRuns)
- validation workspace
- assertEqual "warm relational replacement skips Vampire"
- 0 =<< readIORef warmRuns
- warm <- sole "warm relational replacement module" warmModules
- assertEqual "warm relational replacement interface"
- (Module.sealedTypedModuleSemantic fresh)
- (Module.sealedTypedModuleSemantic warm)
- assertEqual "warm relational replacement prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix fresh))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warm))
-
- let rejectingResolver =
- Declaration.vampireResolver \_prepared ->
- pure
- (Right
- (Provers.CounterSatisfiable
- "relational functionality rejected"))
- runRejected relativePath = do
- failedWorkspace <-
- parseExactWorkspace bootstrap mounts relativePath
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- rejectingResolver
- Declaration.FreshValidation
- (Parse.parsedWorkspaceRootModule failedWorkspace)
- [])
- Module.runTypedModule input
- runRejected failureRelative >>= \case
- Module.TypedModuleFailed _failure prefix -> do
- batches <- pure
- (Declaration.pendingModulePrefixBatches prefix)
- assertEqual "failed relational definition keeps its prefix"
- 1 (length batches)
- prefixBatch <- sole "relational prefix declaration" batches
- assertEqual "failed relational definition publishes no object"
- 1 (length
- (Declaration.committedBatchObjects prefixBatch))
- _result ->
- assertFailure
- "nonfunctional relational definition did not fail"
- runRejected localFailureRelative >>= \case
- Module.TypedModuleFailed _failure prefix ->
- assertBool
- "failed local functionality publishes no theorem"
- (null
- (Declaration.pendingModulePrefixBatches prefix))
- _result ->
- assertFailure
- "nonfunctional local definition did not fail"
-
-assertRelationalReplacementModule
- :: Module.SealedTypedModule
- -> Assertion
-assertRelationalReplacementModule sealed =
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed) of
- [_axiomBatch, definitionBatch, proofBatch] -> do
- _object <- sole "relational replacement object"
- (Declaration.committedBatchObjects definitionBatch)
- let definitionFacts =
- Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta definitionBatch)
- assertEqual "relational replacement fact eligibility"
- [ Semantic.SearchIneligible
- , Semantic.SearchIneligible
- , Semantic.SearchEligible
- ]
- (Semantic.semanticFactSearchEligibility <$> definitionFacts)
- let sourceSafety =
- Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.SourceAxiom)
- assertEqual "relational extensionality inherits functionality safety"
- [ Authority.cleanAuthoritySafety
- , sourceSafety
- , sourceSafety
- ]
- ( Authority.factAuthoritySafety
- . Semantic.semanticFactAuthority
- <$> definitionFacts
- )
- assertEqual "relational replacement has only its equation alias"
- 1
- (length
- (Semantic.declarationDeltaAliases
- (Declaration.committedBatchDelta definitionBatch)))
- validation <-
- maybe
- (assertFailure "relational replacement validation absent"
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation
- definitionBatch)
- case Authority.validationDirectAuthorization
- <$> Semantic.declarationValidationRecordCertificates
- validation of
- [ Authority.CheckedKernelConstruction
- (Authority.CheckedDefinitionEquation equationObject)
- , Authority.CheckedSourceProof [_functionalityRequest]
- , Authority.CheckedKernelConstruction
- (Authority.CheckedSetConstructionExtensionality
- extensionalObject _descriptor)
- ] ->
- assertEqual "relational facts target one object"
- equationObject extensionalObject
- authorizations ->
- assertFailure
- ("unexpected relational authorities "
- <> show authorizations)
- assertEqual "module construction generates no proof row"
- []
- (Declaration.committedBatchProofValidations definitionBatch)
-
- proofValidation <- sole "proof-local relational validation"
- (Declaration.committedBatchProofValidations proofBatch)
- case Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate
- proofValidation) of
- Authority.CheckedSourceProof requests ->
- assertEqual
- "local functionality precedes its continuation"
- 2 (length requests)
- authorization ->
- assertFailure
- ("unexpected proof-local relational authority "
- <> show authorization)
- proofFact <- sole "proof-local relational theorem"
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta proofBatch))
- assertEqual "local extensional premise retains discharge safety"
- sourceSafety
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority proofFact))
- batches ->
- assertFailure
- ("expected relational axiom, definition, and proof, found "
- <> show (length batches))
-
-compilesAndReusesExactFiniteSets :: Assertion
-compilesAndReusesExactFiniteSets =
- Temp.withSystemTempDirectory "felix-exact-finite-set" \root -> do
- let relative = "test/phase5/exact-finite-set.tex"
- sourcePath = root Posix.</> relative
- executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- createDirectoryIfMissing True (Posix.takeDirectory sourcePath)
- ByteString.readFile relative >>= ByteString.writeFile sourcePath
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for exact-finite-set'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts root
- workspace <- parseExactWorkspace bootstrap mounts relative
- observations <- newIORef []
- let resolver = Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- modifyIORef' observations
- (<> [ ( Backend.typedProblemRoute problem
- , Backend.typedProblemAuxiliaryTag
- <$> Vector.toList
- (Backend.typedProblemAuxiliaries problem)
- )
- ])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- freshModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap resolver
- Declaration.FreshValidation
- workspace
- fresh <- sole "fresh finite-set module" freshModules
- assertExactFiniteSetModule "fresh" fresh
- assertEqual
- "finite-set proof uses exactly its FOF characteristics"
- [( Backend.RouteFof
- , [ Foundation.EmptyCharacteristic
- , Foundation.PairSetCharacteristic
- , Foundation.FamilyUnionCharacteristic
- ]
- )]
- =<< readIORef observations
-
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmRuns <- newIORef (0 :: Int)
- warmModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap
- (countingAcceptedResolver executable warmRuns)
- validation
- workspace
- assertEqual "warm finite-set proof skips Vampire"
- 0
- =<< readIORef warmRuns
- warm <- sole "warm finite-set module" warmModules
- assertExactFiniteSetModule "warm" warm
- assertEqual "warm finite-set semantic interface"
- (Module.sealedTypedModuleSemantic fresh)
- (Module.sealedTypedModuleSemantic warm)
- assertEqual "warm finite-set final prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix fresh))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warm))
-
-preparesExactDirectInductives :: Assertion
-preparesExactDirectInductives = do
- foundation <- expectRight Foundation.checkedFoundation
- prepared <-
- expectRight
- =<< prepareExactInductiveFixture
- "test/phase5/exact-inductive.tex"
- assertEqual "exact inductive carrier type"
- (Core.TyArrow Core.TySet Core.TySet)
- (ExactInductive.preparedExactInductiveCarrierType prepared)
- assertEqual "exact inductive carrier body"
- expectedCarrier
- (Core.frozenCoreTerm
- (ExactInductive.preparedExactInductiveCarrierBody prepared))
- assertEqual "foundation guard needs no imported fact"
- []
- (Vector.toList
- (ExactInductive.preparedExactInductiveGuardTargets prepared))
- let facts =
- toList
- (ExactInductive.preparedExactInductiveFacts prepared)
- assertEqual "generated fact order"
- [ Raw.Marker "phase5_fin_intro_1"
- , Raw.Marker "phase5_fin_dom_subset"
- , Raw.Marker "phase5_fin_cases"
- , Raw.Marker "phase5_fin_induct"
- ]
- (TypedInductive.typedInductiveFactMarker <$> facts)
- assertEqual "generated guarded-rule descriptors"
- [ Set.singleton Foundation.SetLfpFixed
- , Set.singleton Foundation.SetLfpBound
- , Set.singleton Foundation.SetLfpFixed
- , Set.singleton Foundation.SetLfpInduct
- ]
- ( Set.fromList
- . toList
- . TypedInductive.typedInductiveFactRules
- <$> facts
- )
- assertBool "generated targets are closed propositions"
- (all
- (\fact ->
- let target = TypedInductive.typedInductiveFactTarget fact
- in Core.frozenCoreType target == Core.TyProp
- && Set.null (Core.frozenCoreGlobals target))
- facts)
-
- let singleton =
- Internal.finiteSet
- Nowhere
- (Internal.EmptySet Nowhere :| [])
- noGlobalType :: Void -> Core.CoreType
- noGlobalType = absurd
- noGlobal
- :: Internal.Symbol
- -> Maybe (TypedInductive.SourceGlobal Void)
- noGlobal = const Nothing
- finite <-
- expectRight
- (TypedInductive.prepareTypedInductive
- noGlobalType
- foundation
- noGlobal
- (Internal.Marker "finite_internal")
- (TypedInductive.DirectInductive
- []
- singleton
- (TypedInductive.DirectInductiveClause
- []
- []
- (Internal.EmptySet Nowhere)
- :| [])))
- finiteGuard <-
- sole
- "finite-set inductive guard"
- (Vector.toList
- (TypedInductive.typedInductiveGuardTargets finite))
- assertEqual
- "typed inductive path uses intrinsic finite-set adjunction"
- (member
- (Core.CIntrinsic Core.Empty)
- (Core.canonicalSetInsert
- (Core.CIntrinsic Core.Empty)
- (Core.CIntrinsic Core.Empty)))
- (Core.frozenCoreTerm finiteGuard)
- where
- apply1 intrinsic argument =
- Core.CApp (Core.CIntrinsic intrinsic) argument
- member element set =
- Core.CApp
- (Core.CApp (Core.CIntrinsic Core.Member) element)
- set
- expectedCarrier =
- Core.CLam Core.TySet
- (Core.CApp
- (Core.CApp
- (Core.CIntrinsic Core.ISetLfp)
- (apply1 Core.UnivOf (Core.CBound 0)))
- (Core.CLam Core.TySet
- (Core.CApp
- (Core.CApp
- (Core.CIntrinsic Core.Sep)
- (apply1 Core.UnivOf (Core.CBound 1)))
- (Core.CLam Core.TySet
- (Core.CEq Core.TySet
- (Core.CBound 0)
- (Core.CBound 2))))))
-
-preparesExactDatatypes :: Assertion
-preparesExactDatatypes = do
- (foundation, owner, prepared) <-
- expectRight
- =<< prepareExactDatatypeFixture
- "test/phase5/exact-datatype.tex"
- let objects =
- toList
- (ExactDatatype.preparedExactDatatypeObjects prepared)
- objectIds = fst <$> objects
- objectTypes = snd <$> objects
- expectedTypes =
- [ Core.TySet
- , Core.TySet
- , Core.TyArrow Core.TySet Core.TySet
- , Core.TyArrow Core.TySet
- (Core.TyArrow Core.TySet Core.TySet)
- ]
- theory = Identity.theoryId foundation
- expectedIds =
- [ Identity.opaqueObjectId theory
- (Identity.opaqueDeclarationSeed
- owner
- (localDeclarationOrdinal 0)
- DatatypeDeclaration
- (generatedObjectSlot index))
- coreType
- | (index, coreType) <- zip [0 ..] expectedTypes
- ]
- assertEqual "datatype opaque object types"
- expectedTypes objectTypes
- assertEqual "datatype opaque object slots"
- expectedIds objectIds
- assertBool "datatype objects are opaque"
- (all ((== Identity.OpaqueObject) . Identity.objectIdFamily) objectIds)
- (carrierId, zeroId, atomId, joinId, constructorIds) <-
- case expectedIds of
- [carrier, zero, atom, join] ->
- pure
- ( carrier
- , zero
- , atom
- , join
- , zero :| [atom, join]
- )
- _ ->
- assertFailure "datatype object inventory is incomplete"
- >> fail "unreachable"
- let facts =
- toList
- (ExactDatatype.preparedExactDatatypeFacts prepared)
- markers =
- ExactDatatype.preparedExactDatatypeFactMarker <$> facts
- assertEqual "datatype generated fact order"
- [ Internal.Marker "phase5_data_phasefivezero_intro"
- , Internal.Marker "phase5_data_phasefiveatom_intro"
- , Internal.Marker "phase5_data_phasefivejoin_intro"
- , Internal.Marker
- "phase5_data_phasefivezero_phasefiveatom_distinct"
- , Internal.Marker
- "phase5_data_phasefivezero_phasefivejoin_distinct"
- , Internal.Marker
- "phase5_data_phasefiveatom_phasefivejoin_distinct"
- , Internal.Marker "phase5_data_phasefiveatom_injective"
- , Internal.Marker "phase5_data_phasefivejoin_injective"
- , Internal.Marker "phase5_data_cases"
- , Internal.Marker "phase5_data_induct"
- ]
- markers
- assertBool "datatype generated targets are checked propositions"
- (all
- (\fact ->
- Core.frozenCoreType
- (ExactDatatype.preparedExactDatatypeFactTarget fact)
- == Core.TyProp)
- facts)
- atomIntroduction <-
- sole "domain-bearing datatype introduction"
- [ fact
- | fact <- facts
- , ExactDatatype.preparedExactDatatypeFactMarker fact
- == Internal.Marker "phase5_data_phasefiveatom_intro"
- ]
- assertEqual "domain-bearing datatype introduction target"
- (Core.CForall Core.TySet
- (Core.CImp
- (member
- (Core.CBound 0)
- singletonEmpty)
- (member
- (Core.CApp
- (Core.CGlobal atomId)
- (Core.CBound 0))
- (Core.CGlobal carrierId))))
- (Core.frozenCoreTerm
- (ExactDatatype.preparedExactDatatypeFactTarget
- atomIntroduction))
- induction <-
- sole "datatype induction law"
- [ fact
- | fact <- facts
- , ExactDatatype.preparedExactDatatypeFactMarker fact
- == Internal.Marker "phase5_data_induct"
- ]
- assertEqual "datatype induction target"
- (Core.CForall Core.TySet
- (Core.CImp
- (conjunctions
- [ member
- (Core.CGlobal zeroId)
- (Core.CBound 0)
- , Core.CForall Core.TySet
- (Core.CImp
- (member
- (Core.CBound 0)
- singletonEmpty)
- (member
- (Core.CApp
- (Core.CGlobal atomId)
- (Core.CBound 0))
- (Core.CBound 1)))
- , Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CImp
- (conjunction
- (member
- (Core.CBound 1)
- (Core.CBound 2))
- (member
- (Core.CBound 0)
- (Core.CBound 2)))
- (member
- (Core.CApp
- (Core.CApp
- (Core.CGlobal joinId)
- (Core.CBound 1))
- (Core.CBound 0))
- (Core.CBound 2))))
- ])
- (Core.CForall Core.TySet
- (Core.CImp
- (member
- (Core.CBound 0)
- (Core.CGlobal carrierId))
- (member
- (Core.CBound 0)
- (Core.CBound 1))))))
- (Core.frozenCoreTerm
- (ExactDatatype.preparedExactDatatypeFactTarget induction))
- assertEqual "datatype descriptor membership"
- (Authority.datatypeCompilationDescriptor
- carrierId
- constructorIds
- (ExactDatatype.preparedExactDatatypeFactReference <$> facts))
- (ExactDatatype.preparedExactDatatypeDescriptor prepared)
- where
- singletonEmpty =
- Core.canonicalSetInsert
- (Core.CIntrinsic Core.Empty)
- (Core.CIntrinsic Core.Empty)
-
- member element set =
- Core.CApp
- (Core.CApp
- (Core.CIntrinsic Core.Member)
- element)
- set
-
- conjunction left right =
- Core.CImp
- (Core.CImp left (Core.CImp right Core.CFalsum))
- Core.CFalsum
-
- conjunctions = \case
- [] -> Core.CImp Core.CFalsum Core.CFalsum
- first : remaining -> foldl' conjunction first remaining
-
-rejectsNestedExactDatatypeRecursion :: Assertion
-rejectsNestedExactDatatypeRecursion = do
- result <-
- prepareExactDatatypeFixture
- "test/phase5/exact-datatype-nested.tex"
- case result of
- Left ExactDatatype.ExactDatatypeInvalid{} -> pure ()
- Left failure ->
- assertFailure
- ("unexpected nested datatype failure: " <> show failure)
- Right _prepared ->
- assertFailure "nested exact datatype recursion was accepted"
-
-compilesAndReusesExactDatatypes :: Assertion
-compilesAndReusesExactDatatypes =
- Temp.withSystemTempDirectory "felix-exact-datatype" \directory -> do
- let relative = "test/phase5/exact-datatype.tex"
- storePath = directory Posix.</> "store.sqlite"
- (foundation, bootstrap, workspace, freshModules) <-
- compileExactFixture relative
- fresh <- sole "fresh exact datatype module" freshModules
- assertExactDatatypeModule "fresh" fresh
- parsed <-
- sole "exact datatype parsed module"
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- let artifact sealed = do
- key <- expectRight
- (Semantic.moduleArtifactKey
- (moduleName (Parse.parsedModuleAddress parsed))
- (Parse.parsedModuleId parsed)
- [ Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic
- (Module.bootstrapPreludeModule bootstrap))
- ]
- (Identity.theoryId foundation))
- pure
- (Semantic.moduleArtifactResult
- key
- (Syntax.moduleSyntaxAssertedId
- (Module.sealedTypedModuleSyntax sealed))
- (Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic sealed)))
- freshArtifact <- artifact fresh
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmModules <-
- compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- unusedResolver
- validation
- workspace
- warm <- sole "warm exact datatype module" warmModules
- assertExactDatatypeModule "warm" warm
- assertEqual "warm exact datatype semantic interface"
- (Module.sealedTypedModuleSemantic fresh)
- (Module.sealedTypedModuleSemantic warm)
- assertEqual "warm exact datatype final prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix fresh))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warm))
- assertEqual "warm exact datatype module artifact"
- freshArtifact
- =<< artifact warm
-
- mounts <- exactFixtureMounts =<< getCurrentDirectory
- nestedWorkspace <-
- parseExactWorkspace bootstrap mounts
- "test/phase5/exact-datatype-nested.tex"
- nestedParsed <-
- sole "nested exact datatype module"
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter
- nestedWorkspace))
- nestedInput <-
- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- unusedResolver
- Declaration.FreshValidation
- nestedParsed
- [])
- Module.runTypedModule nestedInput >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactDatatypeFailed
- (ExactDatatype.ExactDatatypeInvalid
- location _message)))
- prefix -> do
- assertEqual "nested datatype failure line"
- 4
- (locLine location)
- assertBool "nested datatype publishes no prefix"
- (null
- (Declaration.pendingModulePrefixBatches prefix))
- _result ->
- assertFailure "unexpected nested datatype result"
-
-preparesNestedExactInductiveRecursion :: Assertion
-preparesNestedExactInductiveRecursion =
- withAcceptedFixtureVampire "felix-nested-inductive" \vampire -> do
- root <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts root
- workspace <-
- parseExactWorkspace bootstrap mounts
- "test/phase5/exact-inductive-nested.tex"
- parsed <- sole "nested exact inductive parsed module"
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- observed <- newIORef []
- let resolver =
- Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- modifyIORef' observed
- (<> [ ( Backend.typedProblemRoute problem
- , Backend.supportedPropositionTerm
- (Backend.typedProblemClaim problem)
- )
- ])
- (Provers.runPreparedTypedProver vampire prepared)
- modules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap resolver
- Declaration.FreshValidation workspace
- sealed <- sole "nested exact inductive module" modules
- observations <- readIORef observed
- assertEqual "guard proof plus nested monotonicity request count"
- 2 (length observations)
- (route, target) <-
- sole "nested monotonicity request"
- [ observation
- | observation@(_route, candidate) <- observations
- , candidate == expectedPowerMonotonicity
- ]
- assertEqual "nested monotonicity target"
- expectedPowerMonotonicity
- target
- assertEqual "nested monotonicity request is first-order"
- Backend.RouteFof
- route
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed) of
- [_guardBatch, _unsafeBatch, inductiveBatch] -> do
- let facts =
- Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta inductiveBatch)
- aliases =
- Semantic.declarationDeltaAliases
- (Declaration.committedBatchDelta inductiveBatch)
- sourceSafety =
- Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.SourceAxiom)
- assertEqual "nested inductive fact eligibility"
- ( Semantic.SearchEligible
- : Semantic.SearchIneligible
- : replicate 4 Semantic.SearchEligible
- )
- (Semantic.semanticFactSearchEligibility <$> facts)
- monotonicityFact <- case facts of
- _definition : fact : _laws -> pure fact
- _ -> assertFailure "nested inductive fact inventory"
- >> fail "unreachable"
- assertEqual "nested monotonicity fact is unaliased"
- False
- (Semantic.semanticFactFingerprint monotonicityFact
- `elem` (Semantic.semanticAliasTarget <$> aliases))
- assertEqual "nested authority safety reaches generated laws"
- [ Authority.cleanAuthoritySafety
- , sourceSafety
- , sourceSafety
- , Authority.cleanAuthoritySafety
- , sourceSafety
- , sourceSafety
- ]
- ( Authority.factAuthoritySafety
- . Semantic.semanticFactAuthority
- <$> facts
- )
- validation <-
- maybe
- (assertFailure "nested inductive validation is absent"
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation
- inductiveBatch)
- assertEqual "nested inductive candidate authority shape"
- [ "definition"
- , "source-proof"
- , "kernel"
- , "kernel"
- , "kernel"
- , "kernel"
- ]
- (authorizationKind
- . Authority.validationDirectAuthorization
- <$> Semantic.declarationValidationRecordCertificates
- validation)
- requestId <- nestedRequestId inductiveBatch
- Temp.withSystemTempDirectory
- "felix-nested-inductive-cache" \temporary -> do
- let storePath = temporary Posix.</> "store.sqlite"
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix sealed))
- let warmValidation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation
- store)
- (expectRightIO
- . Store.loadDeclarationValidation
- store))
- warmModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap unusedResolver
- warmValidation workspace
- warm <- sole
- "warm nested exact inductive module"
- warmModules
- warmBatch <- case
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix warm) of
- [_warmGuard, _warmUnsafe, batch] -> pure batch
- batches ->
- assertFailure
- ("warm nested batch count: "
- <> show (length batches))
- >> fail "unreachable"
- assertEqual "warm nested exact request"
- requestId
- =<< nestedRequestId warmBatch
- assertEqual "warm nested semantic interface"
- (Module.sealedTypedModuleSemantic sealed)
- (Module.sealedTypedModuleSemantic warm)
- assertEqual "warm nested admitted prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix sealed))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warm))
- freshArtifact <-
- moduleArtifact
- foundation bootstrap parsed sealed
- warmArtifact <-
- moduleArtifact
- foundation bootstrap parsed warm
- assertEqual "warm nested module artifact"
- freshArtifact warmArtifact
- batches ->
- assertFailure
- ("expected guard and nested inductive batches, found "
- <> show (length batches))
-
- failureWorkspace <-
- parseExactWorkspace bootstrap mounts
- "test/phase5/exact-inductive-nested-failure.tex"
- successfulRequests <- newIORef []
- let successfulResolver =
- Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- modifyIORef' successfulRequests
- (<> [Backend.supportedPropositionTerm
- (Backend.typedProblemClaim problem)])
- (Provers.runPreparedTypedProver vampire prepared)
- successfulModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap successfulResolver
- Declaration.FreshValidation failureWorkspace
- successful <- sole
- "successful repeated/distinct nested inductive module"
- successfulModules
- assertEqual
- "repeated and distinct contexts use two monotonicity requests"
- [ expectedPowerMonotonicity
- , expectedDoublePowerMonotonicity
- ]
- =<< readIORef successfulRequests
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix successful) of
- [_guardOne, _guardTwo, batch] -> do
- validation <- maybe
- (assertFailure
- "successful multi-context validation absent"
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation batch)
- assertEqual
- "deduplicated monotonicities precede all kernel laws"
- ( ["definition", "source-proof", "source-proof"]
- <> replicate 6 "kernel"
- )
- (authorizationKind
- . Authority.validationDirectAuthorization
- <$> Semantic.declarationValidationRecordCertificates
- validation)
- batches ->
- assertFailure
- ("successful multi-context batch count: "
- <> show (length batches))
- attempts <- newIORef (0 :: Int)
- let rejectingResolver =
- Declaration.vampireResolver \prepared -> do
- index <- atomicModifyIORef' attempts \current ->
- (current + 1, current)
- if index == 0
- then pure
- (Right
- (Provers.CounterSatisfiable
- "first monotonicity rejected"))
- else
- (Provers.runPreparedTypedProver vampire prepared)
- failureInput <-
- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- rejectingResolver
- Declaration.FreshValidation
- (Parse.parsedWorkspaceRootModule failureWorkspace)
- [])
- Module.runTypedModule failureInput >>= \case
- Module.TypedModuleFailed
- (Module.TypedDeclarationFailed
- (Declaration.ProofObligationFailedAt
- location
- Declaration.VampireObligationRejected{}))
- prefix -> do
- assertEqual "earliest monotonicity failure location"
- 14 (locLine location)
- assertEqual
- "later monotonicity still resolves before first rejection"
- 2 =<< readIORef attempts
- assertEqual
- "rejected monotonicity preserves only earlier declarations"
- 2
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- _result ->
- assertFailure
- "nested monotonicity rejection unexpectedly succeeded"
- where
- authorizationKind = \case
- Authority.CheckedKernelConstruction
- Authority.CheckedDefinitionEquation{} -> "definition"
- Authority.CheckedKernelConstruction{} -> "kernel"
- Authority.CheckedSourceProof{} -> "source-proof"
- authorization -> show authorization
-
- nestedRequestId batch = do
- validation <- maybe
- (assertFailure "nested declaration validation absent"
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation batch)
- certificate <- case
- Semantic.declarationValidationRecordCertificates validation of
- _definition : monotonicity : _laws -> pure monotonicity
- certificates ->
- assertFailure
- ("nested declaration certificate count: "
- <> show (length certificates))
- >> fail "unreachable"
- case Authority.validationDirectAuthorization certificate of
- Authority.CheckedSourceProof [request] -> pure request
- authorization ->
- assertFailure
- ("unexpected nested proof authorization "
- <> show authorization)
- >> fail "unreachable"
-
- moduleArtifact foundation bootstrap parsed sealed = do
- key <- expectRight
- (Semantic.moduleArtifactKey
- (moduleName (Parse.parsedModuleAddress parsed))
- (Parse.parsedModuleId parsed)
- [ Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic
- (Module.bootstrapPreludeModule bootstrap))
- ]
- (Identity.theoryId foundation))
- pure
- (Semantic.moduleArtifactResult
- key
- (Syntax.moduleSyntaxAssertedId
- (Module.sealedTypedModuleSyntax sealed))
- (Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic sealed)))
-
- expectedPowerMonotonicity =
- Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CImp
- (subset (Core.CBound 1) (Core.CBound 0))
- (subset
- (power (Core.CBound 1))
- (power (Core.CBound 0)))))))
-
- expectedDoublePowerMonotonicity =
- Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CImp
- (subset (Core.CBound 1) (Core.CBound 0))
- (subset
- (power (power (Core.CBound 1)))
- (power (power (Core.CBound 0))))))))
-
- power argument =
- Core.CApp (Core.CIntrinsic Core.PowerSet) argument
-
- subset left right =
- Core.CForall Core.TySet
- (Core.CImp
- (member
- (Core.CBound 0)
- (Core.shiftCanonical 1 0 left))
- (member
- (Core.CBound 0)
- (Core.shiftCanonical 1 0 right)))
-
- member element set =
- Core.CApp
- (Core.CApp (Core.CIntrinsic Core.Member) element)
- set
-
-compilesTransparentNestedInductiveWrappers :: Assertion
-compilesTransparentNestedInductiveWrappers =
- withAcceptedFixtureVampire "felix-nested-wrapper" \vampire -> do
- repository <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- mounts <- exactFixtureMounts repository
- workspace <-
- parseExactWorkspace bootstrap mounts
- "test/phase5/exact-inductive-wrapper.tex"
- observed <- newIORef []
- let resolver =
- Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- modifyIORef' observed
- (<> [ ( Backend.typedProblemRoute problem
- , Backend.supportedPropositionTerm
- (Backend.typedProblemClaim problem)
- )
- ])
- (Provers.runPreparedTypedProver vampire prepared)
- modules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap resolver
- Declaration.FreshValidation workspace
- sealed <- sole "transparent-wrapper nested module" modules
- observations <- readIORef observed
- assertEqual "wrapper guard plus monotonicity request count"
- 2 (length observations)
- (route, target) <- case
- [ observation
- | observation@(_route, candidate) <- observations
- , candidate == expectedPowerMonotonicity
- ] of
- [observation] -> pure observation
- matches ->
- assertFailure
- ("normalized wrapper monotonicity matches: "
- <> show matches
- <> "; observed: " <> show observations)
- >> fail "unreachable"
- assertEqual "transparent-wrapper monotonicity is FOF"
- Backend.RouteFof route
- assertEqual "transparent-wrapper monotonicity target"
- expectedPowerMonotonicity target
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed) of
- [_wrapperDefinition, _guardProof, inductiveBatch] -> do
- let facts =
- Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta inductiveBatch)
- assertEqual "transparent-wrapper inductive stays clean"
- (replicate 6 Authority.cleanAuthoritySafety)
- ( Authority.factAuthoritySafety
- . Semantic.semanticFactAuthority
- <$> facts
- )
- validation <- maybe
- (assertFailure
- "transparent-wrapper declaration validation absent"
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation
- inductiveBatch)
- assertEqual "transparent-wrapper staged authority"
- [ "definition"
- , "source-proof"
- , "kernel"
- , "kernel"
- , "kernel"
- , "kernel"
- ]
- (authorizationKind
- . Authority.validationDirectAuthorization
- <$> Semantic.declarationValidationRecordCertificates
- validation)
- batches ->
- assertFailure
- ("transparent-wrapper declaration count: "
- <> show (length batches))
- where
- authorizationKind = \case
- Authority.CheckedKernelConstruction
- Authority.CheckedDefinitionEquation{} -> "definition"
- Authority.CheckedKernelConstruction{} -> "kernel"
- Authority.CheckedSourceProof{} -> "source-proof"
- authorization -> show authorization
-
- expectedPowerMonotonicity =
- Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CImp
- (subset (Core.CBound 1) (Core.CBound 0))
- (subset
- (power (Core.CBound 1))
- (power (Core.CBound 0)))))))
-
- power argument =
- Core.CApp (Core.CIntrinsic Core.PowerSet) argument
-
- subset left right =
- Core.CForall Core.TySet
- (Core.CImp
- (member
- (Core.CBound 0)
- (Core.shiftCanonical 1 0 left))
- (member
- (Core.CBound 0)
- (Core.shiftCanonical 1 0 right)))
-
- member element set =
- Core.CApp
- (Core.CApp (Core.CIntrinsic Core.Member) element)
- set
-
-normalizesNestedExactInductiveContexts :: Assertion
-normalizesNestedExactInductiveContexts = do
- foundation <- expectRight Foundation.checkedFoundation
- powerSymbol <- fixedFunctionSymbol "pow"
- carrierSymbol <- fixedFunctionSymbol "cumul"
- let a = Internal.NamedVar "A"
- x = Internal.NamedVar "x"
- y = Internal.NamedVar "y"
- z = Internal.NamedVar "z"
- carrier =
- Internal.TermOp Nowhere carrierSymbol [Internal.TermVar a]
- powerCarrier =
- Internal.TermOp Nowhere powerSymbol [carrier]
- doublePowerCarrier =
- Internal.TermOp Nowhere powerSymbol [powerCarrier]
- parameterizedCarrier =
- Internal.TermOp Nowhere powerSymbol
- [ Internal.TermOp Nowhere Lexicon.UpairSymbol
- [carrier, Internal.TermVar x]
- ]
- powerContext <-
- expectRight
- (TypedInductive.prepareRecursiveCarrierContext
- carrierSymbol [a] powerCarrier)
- doublePowerContext <-
- expectRight
- (TypedInductive.prepareRecursiveCarrierContext
- carrierSymbol [a] doublePowerCarrier)
- parameterizedContext <-
- expectRight
- (TypedInductive.prepareRecursiveCarrierContext
- carrierSymbol [a] parameterizedCarrier)
- deduplicated <-
- expectRight
- (TypedInductive.prepareTypedInductive
- (const Core.TySet)
- foundation
- (const Nothing)
- (Internal.Marker "nested_dedup")
- (TypedInductive.DirectInductive
- [a]
- (Internal.EmptySet Nowhere)
- (TypedInductive.DirectInductiveClause
- [x, y, z]
- [ TypedInductive.DirectRecursiveCondition
- (Internal.TermVar x) powerContext
- , TypedInductive.DirectRecursiveCondition
- (Internal.TermVar y) powerContext
- , TypedInductive.DirectRecursiveCondition
- (Internal.TermVar z) doublePowerContext
- , TypedInductive.DirectRecursiveCondition
- (Internal.TermVar z) parameterizedContext
- ]
- (Internal.TermVar a)
- :| [])))
- assertEqual "equal contexts deduplicate in first-occurrence order"
- [ monotonicityTarget 4 power
- , monotonicityTarget 4 (power . power)
- , monotonicityTarget 4
- (\hole -> power (pair hole (Core.CBound 4)))
- ]
- ( Core.frozenCoreTerm
- . TypedInductive.typedInductiveMonotonicityTarget
- <$> Vector.toList
- (TypedInductive.typedInductiveMonotonicities deduplicated)
- )
-
- let wrapperSymbol =
- Raw.mkMixfixItem
- [ Just (Internal.Command "phasefivecheckedwrapper")
- , Just Internal.InvisibleBraceL
- , Nothing
- , Just Internal.InvisibleBraceR
- ]
- (Internal.Marker "phasefivecheckedwrapper")
- Raw.NonAssoc
- wrapperCarrier =
- Internal.TermOp Nowhere wrapperSymbol [carrier]
- wrapperContext <-
- expectRight
- (TypedInductive.prepareRecursiveCarrierContext
- carrierSymbol [a] wrapperCarrier)
- wrapperBody <-
- expectRight
- (Core.checkCanonicalCore
- (const Nothing)
- (Core.CLam Core.TySet
- (power (Core.CBound 0))))
- let wrapperId =
- Identity.transparentObjectId
- (Identity.theoryId foundation)
- (Core.TyArrow Core.TySet Core.TySet)
- (Core.frozenCoreTerm wrapperBody)
- wrapped <-
- expectRight
- (TypedInductive.prepareTypedInductive
- (const (Core.TyArrow Core.TySet Core.TySet))
- foundation
- (\symbol ->
- if symbol == Internal.SymbolMixfix wrapperSymbol
- then Just
- (TypedInductive.SourceGlobal
- wrapperId (Just wrapperBody))
- else Nothing)
- (Internal.Marker "nested_wrapper")
- (TypedInductive.DirectInductive
- [a]
- (Internal.EmptySet Nowhere)
- (TypedInductive.DirectInductiveClause
- [x]
- [TypedInductive.DirectRecursiveCondition
- (Internal.TermVar x) wrapperContext]
- (Internal.TermVar a)
- :| [])))
- assertEqual
- "transparent content, not a primitive-name whitelist, owns context semantics"
- [monotonicityTarget 2 power]
- ( Core.frozenCoreTerm
- . TypedInductive.typedInductiveMonotonicityTarget
- <$> Vector.toList
- (TypedInductive.typedInductiveMonotonicities wrapped)
- )
- assertBool "transparent context target contains no wrapper global"
- (all
- (Set.null
- . Core.frozenCoreGlobals
- . TypedInductive.typedInductiveMonotonicityTarget)
- (Vector.toList
- (TypedInductive.typedInductiveMonotonicities wrapped)))
-
- assertExactFailure
- "test/phase5/exact-inductive-wrong-arguments.tex"
- 4
- (\case
- ExactInductive.ExactInductiveRecursiveCarrierWrongArguments{} ->
- True
- _ -> False)
- assertExactFailure
- "test/phase5/exact-inductive-outside-membership.tex"
- 4
- (\case
- ExactInductive.ExactInductiveRecursiveCarrierOutsideMembership{} ->
- True
- _ -> False)
- assertExactFailure
- "test/phase5/exact-inductive-recursive-element.tex"
- 4
- (\case
- ExactInductive.ExactInductiveRecursiveTermMentionsCarrier{} ->
- True
- _ -> False)
- assertExactFailure
- "test/phase5/exact-inductive-recursive-domain.tex"
- 2
- (\case
- ExactInductive.ExactInductiveDomainMentionsCarrier{} -> True
- _ -> False)
- assertExactFailure
- "test/phase5/exact-inductive-recursive-result.tex"
- 4
- (\case
- ExactInductive.ExactInductiveResultMentionsCarrier{} -> True
- _ -> False)
- assertExactFailure
- "test/phase5/exact-inductive-unsupported-context.tex"
- 4
- (\case
- ExactInductive.ExactInductiveUnsupportedRecursiveCarrierContext{} ->
- True
- _ -> False)
- where
- fixedFunctionSymbol marker =
- sole ("fixed function " <> StrictText.unpack marker)
- [ symbol
- | symbol <- Lexicon.prefixOps
- , Raw.mixfixMarker symbol == Internal.Marker marker
- ]
-
- assertExactFailure relative expectedLine expected =
- prepareExactInductiveFixture relative >>= \case
- Left failure
- | expected failure ->
- assertEqual
- ("nested-context failure line for " <> relative)
- expectedLine
- (locLine
- (ExactInductive.exactInductiveErrorLocation
- failure))
- | otherwise ->
- assertFailure
- ("unexpected nested-context failure for "
- <> relative <> ": " <> show failure)
- Right{} ->
- assertFailure
- ("unsupported nested context was accepted: " <> relative)
-
- monotonicityTarget
- :: Int
- -> (Core.CanonicalTerm Identity.ObjectId
- -> Core.CanonicalTerm Identity.ObjectId)
- -> Core.CanonicalTerm Identity.ObjectId
- monotonicityTarget sourceBinders context =
- foldr
- (const (Core.CForall Core.TySet))
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CImp
- (subset (Core.CBound 1) (Core.CBound 0))
- (subset
- (context (Core.CBound 1))
- (context (Core.CBound 0))))))
- [1 .. sourceBinders]
-
- power argument =
- Core.CApp (Core.CIntrinsic Core.PowerSet) argument
-
- pair left right =
- Core.CApp
- (Core.CApp (Core.CIntrinsic Core.PairSet) left)
- right
-
- subset left right =
- Core.CForall Core.TySet
- (Core.CImp
- (member
- (Core.CBound 0)
- (Core.shiftCanonical 1 0 left))
- (member
- (Core.CBound 0)
- (Core.shiftCanonical 1 0 right)))
-
- member element set =
- Core.CApp
- (Core.CApp (Core.CIntrinsic Core.Member) element)
- set
-
-compilesAndReusesExactInductives :: Assertion
-compilesAndReusesExactInductives =
- Temp.withSystemTempDirectory "felix-exact-inductive" \directory -> do
- let relative = "test/phase5/exact-inductive.tex"
- storePath = directory Posix.</> "store.sqlite"
- (foundation, bootstrap, workspace, freshModules) <-
- compileExactFixture relative
- fresh <- sole "fresh exact inductive module" freshModules
- assertExactInductiveModule foundation "fresh" fresh
- parsed <-
- sole "exact inductive parsed module"
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- let artifact sealed = do
- key <- expectRight
- (Semantic.moduleArtifactKey
- (moduleName (Parse.parsedModuleAddress parsed))
- (Parse.parsedModuleId parsed)
- [ Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic
- (Module.bootstrapPreludeModule bootstrap))
- ]
- (Identity.theoryId foundation))
- pure
- (Semantic.moduleArtifactResult
- key
- (Syntax.moduleSyntaxAssertedId
- (Module.sealedTypedModuleSyntax sealed))
- (Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic sealed)))
- freshArtifact <- artifact fresh
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmModules <-
- compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- unusedResolver
- validation
- workspace
- warm <- sole "warm exact inductive module" warmModules
- assertExactInductiveModule foundation "warm" warm
- assertEqual "warm exact inductive semantic interface"
- (Module.sealedTypedModuleSemantic fresh)
- (Module.sealedTypedModuleSemantic warm)
- assertEqual "warm exact inductive final prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix fresh))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warm))
- assertEqual "warm exact inductive module artifact"
- freshArtifact
- =<< artifact warm
-
-authorizesRecursiveExactInductives :: Assertion
-authorizesRecursiveExactInductives =
- Temp.withSystemTempDirectory "felix-recursive-inductive" \directory -> do
- let relative = "test/phase5/exact-inductive-recursive.tex"
- storePath = directory Posix.</> "store.sqlite"
- (foundation, bootstrap, workspace, freshModules) <-
- compileExactFixture relative
- fresh <- sole "fresh recursive inductive module" freshModules
- assertRecursiveExactInductiveModule "fresh" fresh
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmModules <-
- compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- unusedResolver
- validation
- workspace
- warm <- sole "warm recursive inductive module" warmModules
- assertRecursiveExactInductiveModule "warm" warm
- assertEqual "warm recursive inductive semantic interface"
- (Module.sealedTypedModuleSemantic fresh)
- (Module.sealedTypedModuleSemantic warm)
- assertEqual "warm recursive inductive final prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix fresh))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warm))
-
-assertRecursiveExactInductiveModule
- :: String
- -> Module.SealedTypedModule
- -> Assertion
-assertRecursiveExactInductiveModule label sealed =
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed) of
- [_axiomBatch, inductiveBatch] -> do
- object <-
- sole (label <> " recursive inductive carrier")
- (Declaration.committedBatchObjects inductiveBatch)
- let facts =
- Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta inductiveBatch)
- sourceSafety =
- Authority.authoritySafety
- (Authority.singletonEscapeKind
- Authority.SourceAxiom)
- assertEqual (label <> " recursive inductive safety")
- (Authority.cleanAuthoritySafety : replicate 4 sourceSafety)
- ( Authority.factAuthoritySafety
- . Semantic.semanticFactAuthority
- <$> facts
- )
- validation <-
- maybe
- (assertFailure
- (label <> ": recursive validation is absent")
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation
- inductiveBatch)
- assertEqual (label <> " recursive inductive descriptors")
- [ Authority.CheckedKernelConstruction
- (Authority.CheckedDefinitionEquation
- (Identity.assertedObjectId object))
- , guardedRules
- (Foundation.SetLfpBound :| [Foundation.SetLfpFixed])
- , guardedRules (Foundation.SetLfpBound :| [])
- , guardedRules (Foundation.SetLfpFixed :| [])
- , guardedRules (Foundation.SetLfpInduct :| [])
- ]
- ( Authority.validationDirectAuthorization
- <$> Semantic.declarationValidationRecordCertificates
- validation
- )
- batches ->
- assertFailure
- (label <> ": expected axiom and inductive batches, found "
- <> show (length batches))
- where
- guardedRules rules =
- Authority.CheckedKernelConstruction
- (Authority.GuardedFoundationRules
- (Authority.guardedRuleSet rules))
-
-assertExactDatatypeModule
- :: String
- -> Module.SealedTypedModule
- -> Assertion
-assertExactDatatypeModule label sealed = do
- assertEqual (label <> " datatype semantic declaration count")
- 1
- (length
- (Semantic.semanticInterfaceDeclarations
- (Module.sealedTypedModuleSemantic sealed)))
- batch <-
- sole (label <> " datatype declaration batch")
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed))
- let objects = Declaration.committedBatchObjects batch
- objectIds = Identity.assertedObjectId <$> objects
- delta = Declaration.committedBatchDelta batch
- facts = Semantic.declarationDeltaFacts delta
- aliases = Semantic.declarationDeltaAliases delta
- bindings =
- Semantic.semanticEnvironmentBindings
- (Semantic.declarationDeltaEnvironment delta)
- boundIds =
- Semantic.semanticGlobalTargetObject
- . Semantic.semanticGlobalBindingTarget
- <$> bindings
- assertEqual (label <> " datatype object count") 4 (length objects)
- assertBool (label <> " datatype objects are opaque")
- (all
- ((== Identity.OpaqueObject)
- . Identity.objectIdFamily
- . Identity.assertedObjectId)
- objects)
- assertEqual (label <> " datatype global binding count")
- 4
- (length bindings)
- assertBool (label <> " datatype globals are references")
- (all
- (\binding ->
- case Semantic.semanticGlobalBindingTarget binding of
- Semantic.GlobalReference{} -> True
- Semantic.TransparentExpansion{} -> False
- Semantic.ContextualTransparentExpansion{} -> False)
- bindings)
- assertEqual (label <> " datatype global targets")
- (Set.fromList objectIds)
- (Set.fromList boundIds)
- assertEqual (label <> " datatype fact count") 10 (length facts)
- assertEqual (label <> " datatype aliases")
- (Semantic.semanticName <$>
- [ "phase5_data_phasefivezero_intro"
- , "phase5_data_phasefiveatom_intro"
- , "phase5_data_phasefivejoin_intro"
- , "phase5_data_phasefivezero_phasefiveatom_distinct"
- , "phase5_data_phasefivezero_phasefivejoin_distinct"
- , "phase5_data_phasefiveatom_phasefivejoin_distinct"
- , "phase5_data_phasefiveatom_injective"
- , "phase5_data_phasefivejoin_injective"
- , "phase5_data_cases"
- , "phase5_data_induct"
- ])
- (Semantic.semanticAliasName <$> aliases)
- assertBool (label <> " datatype facts are clean")
- (all
- ((== Authority.cleanAuthoritySafety)
- . Authority.factAuthoritySafety
- . Semantic.semanticFactAuthority)
- facts)
- assertEqual (label <> " datatype proof validations")
- []
- (Declaration.committedBatchProofValidations batch)
- validation <-
- maybe
- (assertFailure (label <> ": datatype validation is absent")
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation batch)
- descriptor <-
- case objectIds of
- carrier : firstConstructor : remainingConstructors ->
- pure
- (Authority.datatypeCompilationDescriptor
- carrier
- (firstConstructor :| remainingConstructors)
- ( Authority.factAuthorityTheorem
- . Semantic.semanticFactAuthority
- <$> facts
- ))
- _ ->
- assertFailure (label <> ": datatype object family is absent")
- >> fail "unreachable"
- assertEqual (label <> " datatype validation descriptors")
- (replicate 10
- (Authority.TrustedCompilation
- (Authority.DatatypeCompilation descriptor)))
- ( Authority.validationDirectAuthorization
- <$> Semantic.declarationValidationRecordCertificates validation
- )
-
-assertExactInductiveModule
- :: Foundation.CheckedFoundation
- -> String
- -> Module.SealedTypedModule
- -> Assertion
-assertExactInductiveModule foundation label sealed =
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed) of
- [batch] -> do
- object <-
- sole (label <> " inductive carrier")
- (Declaration.committedBatchObjects batch)
- case Identity.assertedObjectContent object of
- Identity.TransparentObjectContent
- _theory coreType body -> do
- assertEqual (label <> " inductive carrier type")
- (Core.TyArrow Core.TySet Core.TySet)
- coreType
- assertEqual (label <> " inductive carrier identity")
- (Identity.transparentObjectId
- (Identity.theoryId foundation)
- coreType
- body)
- (Identity.assertedObjectId object)
- content ->
- assertFailure
- (label <> ": unexpected inductive carrier "
- <> show content)
- let delta = Declaration.committedBatchDelta batch
- facts = Semantic.declarationDeltaFacts delta
- aliases = Semantic.declarationDeltaAliases delta
- assertEqual (label <> " inductive fact count")
- 5
- (length facts)
- assertEqual (label <> " inductive aliases")
- (Semantic.semanticName <$>
- [ "phase5_fin"
- , "phase5_fin_intro_1"
- , "phase5_fin_dom_subset"
- , "phase5_fin_cases"
- , "phase5_fin_induct"
- ])
- (Semantic.semanticAliasName <$> aliases)
- assertBool (label <> " inductive facts are clean")
- (all
- ((== Authority.cleanAuthoritySafety)
- . Authority.factAuthoritySafety
- . Semantic.semanticFactAuthority)
- facts)
- assertEqual (label <> " inductive proof validations")
- []
- (Declaration.committedBatchProofValidations batch)
- validation <-
- maybe
- (assertFailure
- (label <> ": inductive validation is absent")
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation batch)
- assertEqual (label <> " inductive validation descriptors")
- [ Authority.CheckedKernelConstruction
- (Authority.CheckedDefinitionEquation
- (Identity.assertedObjectId object))
- , guardedRules (Foundation.SetLfpFixed :| [])
- , guardedRules (Foundation.SetLfpBound :| [])
- , guardedRules (Foundation.SetLfpFixed :| [])
- , guardedRules (Foundation.SetLfpInduct :| [])
- ]
- ( Authority.validationDirectAuthorization
- <$> Semantic.declarationValidationRecordCertificates
- validation
- )
- batches ->
- assertFailure
- (label <> ": expected one inductive batch, found "
- <> show (length batches))
- where
- guardedRules rules =
- Authority.CheckedKernelConstruction
- (Authority.GuardedFoundationRules
- (Authority.guardedRuleSet rules))
-
-assertExactFiniteSetModule
- :: String
- -> Module.SealedTypedModule
- -> Assertion
-assertExactFiniteSetModule label sealed = do
- assertEqual (label <> " finite-set semantic declarations")
- 2
- (length
- (Semantic.semanticInterfaceDeclarations
- (Module.sealedTypedModuleSemantic sealed)))
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed) of
- [definitionBatch, theoremBatch] -> do
- definitionObject <- sole
- (label <> " finite-set definition object")
- (Declaration.committedBatchObjects definitionBatch)
- case Identity.assertedObjectContent definitionObject of
- Identity.TransparentObjectContent
- _theory coreType body -> do
- assertEqual (label <> " finite-set definition type")
- (Core.TyArrow Core.TySet
- (Core.TyArrow Core.TySet Core.TySet))
- coreType
- assertEqual (label <> " finite-set definition body")
- expectedBody
- body
- content ->
- assertFailure
- (label <> ": unexpected finite-set object "
- <> show content)
- assertEqual (label <> " finite-set definition fact count")
- 1
- (length
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta definitionBatch)))
- assertEqual (label <> " finite-set definition proof validations")
- []
- (Declaration.committedBatchProofValidations definitionBatch)
-
- assertEqual (label <> " finite-set theorem adds no object")
- []
- (Declaration.committedBatchObjects theoremBatch)
- theoremFact <- sole
- (label <> " finite-set theorem fact")
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta theoremBatch))
- assertEqual (label <> " finite-set theorem safety")
- Authority.cleanAuthoritySafety
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority theoremFact))
- theoremValidation <- sole
- (label <> " finite-set theorem validation")
- (Declaration.committedBatchProofValidations theoremBatch)
- case Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate
- theoremValidation) of
- Authority.CheckedSourceProof [_request] ->
- pure ()
- authorization ->
- assertFailure
- (label <> ": unexpected finite-set theorem authority "
- <> show authorization)
- batches ->
- assertFailure
- (label <> ": expected finite-set definition and theorem, found "
- <> show (length batches))
- where
- expectedBody =
- Core.CLam Core.TySet
- (Core.CLam Core.TySet
- (Core.canonicalSetInsert
- (Core.CBound 1)
- (Core.canonicalSetInsert
- (Core.CBound 0)
- (Core.CIntrinsic Core.Empty))))
-
-assertExactSeparationModule
- :: String
- -> Module.SealedTypedModule
- -> Assertion
-assertExactSeparationModule label sealed = do
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed) of
- [definitionBatch, theoremBatch] -> do
- assertEqual (label <> " separation definition object count")
- 1
- (length
- (Declaration.committedBatchObjects definitionBatch))
- definitionObject <- sole
- (label <> " separation definition object")
- (Declaration.committedBatchObjects definitionBatch)
- case Identity.assertedObjectContent definitionObject of
- Identity.TransparentObjectContent
- _theory coreType body -> do
- assertEqual (label <> " separation definition type")
- (Core.TyArrow Core.TySet Core.TySet)
- coreType
- assertEqual (label <> " separation definition body")
- (Core.CLam Core.TySet
- (Core.CApp
- (Core.CApp
- (Core.CIntrinsic Core.Sep)
- (Core.CBound 0))
- (Core.CLam Core.TySet
- (Core.CEq Core.TySet
- (Core.CBound 0)
- (Core.CBound 0)))))
- body
- content ->
- assertFailure
- (label <> ": unexpected separation object "
- <> show content)
- let definitionDelta =
- Declaration.committedBatchDelta definitionBatch
- definitionFacts =
- Semantic.declarationDeltaFacts definitionDelta
- assertEqual (label <> " definition fact count")
- 2 (length definitionFacts)
- assertEqual (label <> " defining equation is explicit-only")
- [Semantic.SearchIneligible, Semantic.SearchEligible]
- (Semantic.semanticFactSearchEligibility <$> definitionFacts)
- assertEqual (label <> " generated view is unaliased")
- 1
- (length (Semantic.declarationDeltaAliases definitionDelta))
- assertEqual (label <> " definition proposition count")
- 2
- (length
- (Declaration.committedBatchPropositions definitionBatch))
- assertEqual (label <> " definition proof validations")
- []
- (Declaration.committedBatchProofValidations definitionBatch)
- definitionValidation <-
- maybe
- (assertFailure
- (label <> ": definition validation is absent")
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation
- definitionBatch)
- case Authority.validationDirectAuthorization
- <$> Semantic.declarationValidationRecordCertificates
- definitionValidation of
- [ Authority.CheckedKernelConstruction
- (Authority.CheckedDefinitionEquation target)
- , Authority.CheckedKernelConstruction
- (Authority.CheckedSetConstructionExtensionality
- generatedTarget _descriptor)
- ] ->
- assertEqual
- (label <> " construction authority object")
- target generatedTarget
- authorizations ->
- assertFailure
- (label <> ": unexpected definition authorities "
- <> show authorizations)
-
- assertEqual (label <> " theorem adds no object")
- []
- (Declaration.committedBatchObjects theoremBatch)
- theoremFact <- sole
- (label <> " separation theorem fact")
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta theoremBatch))
- assertEqual (label <> " theorem safety")
- Authority.cleanAuthoritySafety
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority theoremFact))
- theoremValidation <- sole
- (label <> " separation theorem validation")
- (Declaration.committedBatchProofValidations theoremBatch)
- case Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate
- theoremValidation) of
- Authority.CheckedSourceProof [_request] ->
- pure ()
- authorization ->
- assertFailure
- (label <> ": unexpected theorem authority "
- <> show authorization)
- batches ->
- assertFailure
- (label <> ": expected definition and theorem, found "
- <> show (length batches))
-
-reusesExactSeparationValidation :: Assertion
-reusesExactSeparationValidation =
- Temp.withSystemTempDirectory "felix-exact-separation-cache" \root -> do
- let relative = "test/phase5/exact-separation.tex"
- sourcePath = root Posix.</> relative
- executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- createDirectoryIfMissing True (Posix.takeDirectory sourcePath)
- ByteString.readFile relative >>= ByteString.writeFile sourcePath
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for exact-separation-cache'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts root
- workspace <- parseExactWorkspace bootstrap mounts relative
- freshRequests <- newIORef []
- let freshResolver = Declaration.vampireResolver \prepared -> do
- modifyIORef' freshRequests
- (<> [Provers.preparedTypedProverRequest prepared])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- freshModules <-
- compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- freshResolver
- Declaration.FreshValidation
- workspace
- assertEqual "fresh separation proof runs Vampire once"
- 1
- . length
- =<< readIORef freshRequests
- fresh <- sole "fresh exact separation module" freshModules
- assertExactSeparationModule "fresh cached" fresh
- freshDefinitionBatch <-
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix fresh) of
- batch : _theorem : [] -> pure batch
- batches ->
- assertFailure
- ("fresh separation declaration count: "
- <> show (length batches))
- >> fail "unreachable"
- freshDefinitionValidation <-
- maybe
- (assertFailure "fresh separation definition validation absent"
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation
- freshDefinitionBatch)
- corruptedDefinitionValidation <-
- case Semantic.declarationValidationRecordCertificates
- freshDefinitionValidation of
- [equation, extensional] -> do
- corruptedExtensional <-
- expectRight
- (Authority.validationCertificate
- (Authority.validationTarget extensional)
- (Authority.validationDirectAuthorization
- equation))
- pure
- (Semantic.declarationValidationRecord
- (Semantic.declarationValidationRecordKey
- freshDefinitionValidation)
- [equation, corruptedExtensional])
- certificates ->
- assertFailure
- ("fresh separation certificate count: "
- <> show (length certificates))
- >> fail "unreachable"
- freshRequest <-
- sole "fresh separation request"
- =<< readIORef freshRequests
- freshAcceptedRequest <-
- acceptedRequestId "fresh separation" fresh
- assertEqual "fresh authority binds the exact request bytes"
- freshAcceptedRequest
- (Provers.preparedVerificationRequestId freshRequest)
- assertBool "fresh separation request bytes are retained by the caller"
- (Provers.preparedVerificationByteCount freshRequest > 0)
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmRuns <- newIORef (0 :: Int)
- warmModules <-
- compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- (countingAcceptedResolver executable warmRuns)
- validation
- workspace
- assertEqual "warm separation proof skips Vampire"
- 0
- =<< readIORef warmRuns
- warm <- sole "warm exact separation module" warmModules
- assertExactSeparationModule "warm cached" warm
- warmAcceptedRequest <-
- acceptedRequestId "warm separation" warm
- assertEqual
- "warm validation retains the fresh request-byte identity"
- freshAcceptedRequest
- warmAcceptedRequest
- assertEqual "warm separation semantic interface"
- (Module.sealedTypedModuleSemantic fresh)
- (Module.sealedTypedModuleSemantic warm)
- assertEqual "warm separation final prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix fresh))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warm))
- let components sealed =
- let batches =
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed)
- in ( concatMap
- Declaration.committedBatchObjects
- batches
- , concatMap
- (fmap Identity.checkedPropositionId
- . Declaration.committedBatchPropositions)
- batches
- , concatMap
- Declaration.committedBatchProofValidations
- batches
- , Declaration.committedBatchDeclarationValidation
- <$> batches
- )
- assertEqual "warm separation checked artifacts"
- (components fresh)
- (components warm)
- corruptRuns <- newIORef (0 :: Int)
- let corruptedValidation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (\key ->
- if key
- == Semantic.declarationValidationRecordKey
- corruptedDefinitionValidation
- then pure
- (Just corruptedDefinitionValidation)
- else expectRightIO
- (Store.loadDeclarationValidation
- store key)))
- corrupted <- Exception.try
- (compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- (countingAcceptedResolver executable corruptRuns)
- corruptedValidation
- workspace)
- :: IO
- (Either
- Declaration.ValidationIntegrityError
- [Module.SealedTypedModule])
- case corrupted of
- Left Declaration.CachedValidationIntegrityError{} ->
- pure ()
- Right _ ->
- assertFailure
- "mismatched generated authority replay succeeded"
- assertEqual
- "mismatched generated authority does not invoke Vampire"
- 0
- =<< readIORef corruptRuns
- where
- acceptedRequestId label sealed = do
- theoremBatch <-
- case Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed) of
- [_definitionBatch, batch] -> pure batch
- batches ->
- assertFailure
- (label <> ": unexpected declaration count "
- <> show (length batches))
- >> fail "unreachable"
- validation <- sole
- (label <> " proof validation")
- (Declaration.committedBatchProofValidations theoremBatch)
- case Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate validation) of
- Authority.CheckedSourceProof [request] -> pure request
- authorization ->
- assertFailure
- (label <> ": unexpected direct authorization "
- <> show authorization)
- >> fail "unreachable"
-
-compilesExactSourceAxioms :: Assertion
-compilesExactSourceAxioms =
- Temp.withSystemTempDirectory "felix-exact-source-axiom" \root -> do
- let storePath = root Posix.</> "store.sqlite"
- (foundation, bootstrap, workspace, freshModules) <-
- compileExactFixture
- "test/phase5/exact-source-axiom-assumptions.tex"
- fresh <- sole "fresh source-axiom module" freshModules
- assertSourceAxiom "fresh" fresh
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix fresh))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap unusedResolver validation workspace
- warm <- sole "warm source-axiom module" warmModules
- assertSourceAxiom "warm" warm
- assertEqual "warm source axiom preserves semantics"
- (Module.sealedTypedModuleSemantic fresh)
- (Module.sealedTypedModuleSemantic warm)
- assertEqual "warm source axiom preserves prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix fresh))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix warm))
- where
- assertSourceAxiom label sealed = do
- batch <- sole (label <> " source-axiom batch")
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed))
- fact <- sole (label <> " source-axiom fact")
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch))
- alias <- sole (label <> " source-axiom alias")
- (Semantic.declarationDeltaAliases
- (Declaration.committedBatchDelta batch))
- assertEqual (label <> " source-axiom search eligibility")
- Semantic.SearchEligible
- (Semantic.semanticFactSearchEligibility fact)
- assertEqual (label <> " source-axiom marker alias")
- (Semantic.semanticName "phase5_exact_source_axiom_assumptions")
- (Semantic.semanticAliasName alias)
- proposition <- sole (label <> " source-axiom proposition")
- (Declaration.committedBatchPropositions batch)
- assertEqual (label <> " source-axiom closed target")
- (Core.CForall Core.TySet
- (Core.CForall Core.TySet
- (Core.CImp
- (member (Core.CBound 0) (Core.CBound 1))
- (Core.CImp
- (Core.CEq Core.TySet
- (Core.CBound 0)
- (Core.CBound 0))
- (member
- (Core.CBound 0)
- (Core.CBound 1))))))
- (Core.frozenCoreTerm
- (Identity.checkedPropositionTerm proposition))
- assertEqual (label <> " source-axiom safety")
- (Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.SourceAxiom))
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority fact))
- validation <-
- maybe
- (assertFailure (label <> " source-axiom validation is absent")
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation batch)
- certificate <- sole (label <> " source-axiom certificate")
- (Semantic.declarationValidationRecordCertificates validation)
- assertEqual (label <> " source-axiom direct authority")
- Authority.SourceAxiomAuthorization
- (Authority.validationDirectAuthorization certificate)
- assertEqual (label <> " source axiom has no proof validations")
- []
- (Declaration.committedBatchProofValidations batch)
-
- member element set =
- Core.CApp
- (Core.CApp
- (Core.CIntrinsic Core.Member)
- element)
- set
-
-rejectsProofLocalGeneralization :: Assertion
-rejectsProofLocalGeneralization = do
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- repository <- getCurrentDirectory
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace
- bootstrap mounts
- "test/phase5/exact-proof-local-free.tex"
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- unusedResolver
- Declaration.FreshValidation
- (Parse.parsedWorkspaceRootModule workspace)
- [])
- Module.runTypedModule input >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactProofFailed
- (ExactProof.ExactProofElaborationFailed
- (Exact.ExactFreeVariable location
- (Raw.NamedVar "y")))))
- prefix -> do
- assertEqual "proof-local free variable line"
- 6 (locLine location)
- assertEqual "proof-local failure commits nothing"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Module.TypedModuleSucceeded{} ->
- assertFailure "proof-local variable was generalized"
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("proof-local generalization module did not open: "
- <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("unexpected proof-local generalization failure: "
- <> show failure)
-
-doesNotTreatMarkerOnlyNounAsSet :: Assertion
-doesNotTreatMarkerOnlyNounAsSet = do
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- repository <- getCurrentDirectory
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace
- bootstrap mounts
- "test/phase5/exact-set-marker.tex"
- Temp.withSystemTempDirectory "felix-exact-set-marker" \root -> do
- let executable = root Posix.</> "vampire"
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for set-marker'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- observed <- newIORef []
- let resolver = Declaration.vampireResolver \prepared -> do
- let problem =
- Provers.preparedTypedProverLogicalProblem prepared
- claim = Backend.typedProblemClaim problem
- locals = Backend.typedProblemLocalPremises problem
- modifyIORef' observed
- (<> [ [ Backend.supportedPropositionTerm
- (Backend.typedLocalPremiseProposition premise)
- == Backend.supportedPropositionTerm claim
- | premise <- Vector.toList locals
- ]
- ])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- resolver
- Declaration.FreshValidation
- (Parse.parsedWorkspaceRootModule workspace)
- [])
- Module.runTypedModule input >>= \case
- Module.TypedModuleSucceeded{} ->
- assertEqual
- "the source noun supplies the local proof premise"
- [[True]]
- =<< readIORef observed
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("marker-only set noun module did not open: "
- <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("unexpected marker-only set noun failure: "
- <> show failure)
-
-compilesExactOmittedProofs :: Assertion
-compilesExactOmittedProofs =
- Temp.withSystemTempDirectory "felix-exact-omitted" \root -> do
- repository <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace
- bootstrap mounts "test/phase5/exact-omitted.tex"
- let executable = root Posix.</> "vampire"
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for exact-omitted'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- calls <- newIORef (0 :: Int)
- let resolver = Declaration.vampireResolver \prepared -> do
- modifyIORef' calls (+ 1)
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- modules <-
- compileParsedWorkspaceWithResolver
- foundation bootstrap resolver workspace
- sealed <- sole "exact omitted module" modules
- assertEqual "only the non-omitted continuation invokes Vampire"
- 1
- =<< readIORef calls
- let batches =
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix sealed)
- assertEqual "top-level and nested omitted declarations"
- 2 (length batches)
- for_ (zip ["top-level", "nested"] batches) \(label, batch) -> do
- fact <- sole (label <> " omitted fact")
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch))
- assertEqual (label <> " omitted safety")
- (Authority.authoritySafety
- (Authority.singletonEscapeKind Authority.Omitted))
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority fact))
- record <- sole (label <> " omitted validation")
- (Declaration.committedBatchProofValidations batch)
- assertEqual (label <> " omitted direct authority")
- Authority.OmittedAuthorization
- (Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate record))
- assertEqual (label <> " publishes only its final theorem")
- 1
- (length
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch)))
-
-reusesExactEscapeAuthority :: Assertion
-reusesExactEscapeAuthority =
- Temp.withSystemTempDirectory "felix-exact-escape-cache" \root -> do
- let consumerRelative = "test/phase5/exact-escape-consumer.tex"
- producerRelative = "test/phase5/exact-escape-producer.tex"
- consumerPath = root Posix.</> consumerRelative
- producerPath = root Posix.</> producerRelative
- executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- createDirectoryIfMissing True (Posix.takeDirectory consumerPath)
- consumerSource <- ByteString.readFile consumerRelative
- producerSource <- ByteString.readFile producerRelative
- ByteString.writeFile consumerPath consumerSource
- ByteString.writeFile producerPath producerSource
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for exact-escape'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- mounts <- exactFixtureMounts root
- freshWorkspace <-
- parseExactWorkspace bootstrap mounts consumerRelative
- freshRuns <- newIORef (0 :: Int)
- freshModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap
- (acceptedResolver executable freshRuns)
- Declaration.FreshValidation
- freshWorkspace
- assertEqual "fresh escape graph Vampire requests"
- 5
- =<< readIORef freshRuns
- assertEscapeGraph "fresh" freshModules
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- traverse_
- (expectRightIO
- . Store.writePendingModulePrefix store
- . Module.sealedTypedModulePrefix)
- freshModules
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- compileWarm workspace = do
- runs <- newIORef (0 :: Int)
- modules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap
- (acceptedResolver executable runs)
- validation
- workspace
- runCount <- readIORef runs
- pure (modules, runCount)
- (warmModules, warmRuns) <- compileWarm freshWorkspace
- assertEqual "exact escape warm hit skips Vampire"
- 0 warmRuns
- assertEscapeGraph "warm" warmModules
- assertEqual "warm escape graph preserves module semantics"
- (moduleSemantics freshModules)
- (moduleSemantics warmModules)
- assertEqual "warm escape graph preserves module prefixes"
- (modulePrefixes freshModules)
- (modulePrefixes warmModules)
-
- let formattingOnly =
- Text.encodeUtf8
- ("% shifted exact escape source\n"
- <> Text.decodeUtf8 consumerSource)
- ByteString.writeFile consumerPath formattingOnly
- formattedWorkspace <-
- parseExactWorkspace bootstrap mounts consumerRelative
- assertBool "formatting changes the escape parsed identity"
- (Parse.parsedModuleId
- (Parse.parsedWorkspaceRootModule freshWorkspace)
- /= Parse.parsedModuleId
- (Parse.parsedWorkspaceRootModule
- formattedWorkspace))
- (formattedModules, formattedRuns) <-
- compileWarm formattedWorkspace
- assertEqual "formatting-only escape edit reuses validation"
- 0 formattedRuns
- assertEqual "formatting-only escape edit preserves semantics"
- (moduleSemantics freshModules)
- (moduleSemantics formattedModules)
-
- let omittedGoalEdit =
- Text.encodeUtf8
- (StrictText.replace
- " Show $x = x$."
- " Show if $x = x$, then $x = x$."
- (Text.decodeUtf8 consumerSource))
- ByteString.writeFile consumerPath omittedGoalEdit
- editedWorkspace <-
- parseExactWorkspace bootstrap mounts consumerRelative
- (editedModules, editedRuns) <-
- compileWarm editedWorkspace
- assertEqual "changed omitted goal misses its proof validation"
- 1 editedRuns
- assertEqual "changed omitted goal preserves public semantics"
- (moduleSemantics freshModules)
- (moduleSemantics editedModules)
- where
- acceptedResolver executable runs =
- Declaration.vampireResolver \prepared -> do
- modifyIORef' runs (+ 1)
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
-
- moduleSemantics = fmap Module.sealedTypedModuleSemantic
- modulePrefixes =
- fmap
- (Declaration.pendingModulePrefixCurrent
- . Module.sealedTypedModulePrefix)
-
- assertEscapeGraph label = \case
- [producer, consumer] -> do
- let producerBatches =
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix producer)
- consumerBatches =
- Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix consumer)
- case producerBatches of
- [sourceAxiom, omitted] -> do
- assertEscapeSafety
- (label <> " source axiom")
- [Authority.SourceAxiom]
- sourceAxiom
- assertDeclarationDirect
- (label <> " source axiom")
- Authority.SourceAxiomAuthorization
- sourceAxiom
- assertEscapeSafety
- (label <> " omitted theorem")
- [Authority.Omitted]
- omitted
- assertProofDirectOmitted
- (label <> " omitted theorem")
- omitted
- batches ->
- assertFailure
- (label <> " producer batch count: "
- <> show (length batches))
- case consumerBatches of
- [fromAxiom, fromOmitted, throughLocal, ownOmission] -> do
- assertEscapeSafety
- (label <> " source-axiom consumer")
- [Authority.SourceAxiom]
- fromAxiom
- assertProofDirectChecked
- (label <> " source-axiom consumer") 1 fromAxiom
- assertEscapeSafety
- (label <> " omitted consumer")
- [Authority.Omitted]
- fromOmitted
- assertProofDirectChecked
- (label <> " omitted consumer") 1 fromOmitted
- assertEscapeSafety
- (label <> " local source-axiom consumer")
- [Authority.SourceAxiom]
- throughLocal
- assertProofDirectChecked
- (label <> " local source-axiom consumer")
- 2 throughLocal
- assertEscapeSafety
- (label <> " own omission")
- [Authority.SourceAxiom, Authority.Omitted]
- ownOmission
- assertProofDirectOmitted
- (label <> " own omission") ownOmission
- batches ->
- assertFailure
- (label <> " consumer batch count: "
- <> show (length batches))
- modules ->
- assertFailure
- (label <> " escape module count: "
- <> show (length modules))
-
- assertEscapeSafety label expected batch = do
- fact <- sole (label <> " fact")
- (Semantic.declarationDeltaFacts
- (Declaration.committedBatchDelta batch))
- assertEqual (label <> " public escape kinds")
- expected
- (Authority.escapeKindsToList
- (Authority.authoritySafetyEscapeKinds
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority fact))))
-
- assertDeclarationDirect label expected batch = do
- validation <-
- maybe
- (assertFailure (label <> " declaration validation is absent")
- >> fail "unreachable")
- pure
- (Declaration.committedBatchDeclarationValidation batch)
- certificate <- sole (label <> " declaration certificate")
- (Semantic.declarationValidationRecordCertificates validation)
- assertEqual (label <> " direct authorization")
- expected
- (Authority.validationDirectAuthorization certificate)
-
- assertProofDirectChecked label expectedCount batch = do
- authorization <- proofDirect label batch
- case authorization of
- Authority.CheckedSourceProof requests ->
- assertEqual (label <> " accepted request count")
- expectedCount (length requests)
- direct ->
- assertFailure
- (label <> " has unexpected direct authority: "
- <> show direct)
-
- assertProofDirectOmitted label batch = do
- authorization <- proofDirect label batch
- assertEqual (label <> " direct authorization")
- Authority.OmittedAuthorization authorization
-
- proofDirect label batch = do
- record <- sole (label <> " proof validation")
- (Declaration.committedBatchProofValidations batch)
- pure
- (Authority.validationDirectAuthorization
- (Semantic.proofValidationRecordCertificate record))
-
-rejectsAfterExactOmittedSubclaim :: Assertion
-rejectsAfterExactOmittedSubclaim =
- Temp.withSystemTempDirectory "felix-exact-omitted-rollback" \root -> do
- repository <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace
- bootstrap mounts "test/phase5/exact-escape-consumer.tex"
- parsedModules <-
- pure
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- (producerParsed, consumerParsed) <-
- case parsedModules of
- [producer, consumer] -> pure (producer, consumer)
- modules ->
- assertFailure
- ("unexpected rollback graph size: "
- <> show (length modules))
- >> fail "unreachable"
- producerInput <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- unusedResolver
- Declaration.FreshValidation
- producerParsed
- [])
- producer <- Module.runTypedModule producerInput >>= \case
- Module.TypedModuleSucceeded sealed -> pure sealed
- _ ->
- assertFailure "escape producer did not seal"
- >> fail "unreachable"
- let executable = root Posix.</> "vampire"
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for omitted-rollback'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- calls <- newIORef (0 :: Int)
- let resolver = Declaration.vampireResolver \prepared -> do
- runCount <- readIORef calls
- modifyIORef' calls (+ 1)
- if runCount < 4
- then
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- else
- pure
- (Right
- (Provers.CounterSatisfiable
- "rejected continuation"))
- consumerInput <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- resolver
- Declaration.FreshValidation
- consumerParsed
- [producer])
- Module.runTypedModule consumerInput >>= \case
- Module.TypedModuleFailed
- (Module.TypedDeclarationFailed
- (Declaration.ProofObligationFailedAt
- location
- Declaration.VampireObligationRejected{}))
- prefix -> do
- assertEqual "the continuation is the fifth request"
- 5
- =<< readIORef calls
- assertEqual "rejected continuation location"
- 37 (locLine location)
- assertEqual "omitted declaration rolls back atomically"
- 3
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Module.TypedModuleSucceeded{} ->
- assertFailure "rejected omitted continuation was accepted"
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("omitted rollback module did not open: "
- <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("unexpected omitted rollback failure: "
- <> show failure)
-
-reusesExactProofValidationAcrossModuleMisses :: Assertion
-reusesExactProofValidationAcrossModuleMisses =
- Temp.withSystemTempDirectory "felix-exact-proof-cache" \root -> do
- let relative = "test/phase5/exact-proofs.tex"
- producerRelative = "test/phase5/exact-producer.tex"
- sourcePath = root Posix.</> relative
- producerPath = root Posix.</> producerRelative
- executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- createDirectoryIfMissing True (Posix.takeDirectory sourcePath)
- original <- ByteString.readFile relative
- producer <- ByteString.readFile producerRelative
- ByteString.writeFile sourcePath original
- ByteString.writeFile producerPath producer
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for exact-cache'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts root
- freshWorkspace <- parseExactWorkspace bootstrap mounts relative
- freshRuns <- newIORef (0 :: Int)
- freshModules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap
- (countingAcceptedResolver executable freshRuns)
- Declaration.FreshValidation
- freshWorkspace
- assertEqual "fresh proof obligations run Vampire"
- 7
- =<< readIORef freshRuns
- freshRoot <- sole "fresh exact proof root" (drop 1 freshModules)
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- traverse_
- (expectRightIO
- . Store.writePendingModulePrefix store
- . Module.sealedTypedModulePrefix)
- freshModules
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- compileWarm workspace = do
- runs <- newIORef (0 :: Int)
- modules <-
- compileParsedWorkspaceWithValidation
- foundation bootstrap
- (countingAcceptedResolver executable runs)
- validation
- workspace
- rootModule <- sole "warm exact proof root" (drop 1 modules)
- runCount <- readIORef runs
- pure (rootModule, runCount)
- (unchangedRoot, unchangedRuns) <-
- compileWarm freshWorkspace
- assertEqual "exact warm hit skips Vampire"
- 0 unchangedRuns
- assertEqual "exact warm hit preserves public semantics"
- (Module.sealedTypedModuleSemantic freshRoot)
- (Module.sealedTypedModuleSemantic unchangedRoot)
-
- let formattingOnly =
- Text.encodeUtf8
- (StrictText.replace
- "\\begin{proposition}\\label{phase5_structural_proof}"
- ("% shifted source location\n"
- <> "\\begin{proposition}\\label{phase5_structural_proof}")
- (Text.decodeUtf8 original))
- ByteString.writeFile sourcePath formattingOnly
- formattedWorkspace <-
- parseExactWorkspace bootstrap mounts relative
- assertBool "formatting changes parsed module identity"
- (Parse.parsedModuleId
- (Parse.parsedWorkspaceRootModule freshWorkspace)
- /= Parse.parsedModuleId
- (Parse.parsedWorkspaceRootModule formattedWorkspace))
- (formattedRoot, formattedRuns) <-
- compileWarm formattedWorkspace
- assertEqual "formatting-only module miss reuses proof validation"
- 0 formattedRuns
- assertEqual "formatting-only miss preserves public semantics"
- (Module.sealedTypedModuleSemantic freshRoot)
- (Module.sealedTypedModuleSemantic formattedRoot)
-
- let semanticEdit =
- Text.encodeUtf8
- (StrictText.replace
- " We have $x = x$ by assumption."
- (StrictText.intercalate "\n"
- [ " Show $x = x$."
- , " \\begin{subproof}"
- , " Follows by assumption."
- , " \\end{subproof}"
- ])
- (Text.decodeUtf8 original))
- ByteString.writeFile sourcePath semanticEdit
- editedWorkspace <-
- parseExactWorkspace bootstrap mounts relative
- (editedRoot, editedRuns) <-
- compileWarm editedWorkspace
- assertEqual "semantic proof edit reruns its obligations"
- 2 editedRuns
- assertEqual "request-equivalent proof preserves public semantics"
- (Module.sealedTypedModuleSemantic freshRoot)
- (Module.sealedTypedModuleSemantic editedRoot)
-rejectsFixedSemanticDeclaration :: Assertion
-rejectsFixedSemanticDeclaration =
- Temp.withSystemTempDirectory "felix-fixed-semantic" \root -> do
- let relative = "entry.tex"
- path = root Posix.</> relative
- source =
- "\\begin{signature}\\label{source_unions}\n"
- <> " $\\unions{X}$ is a set.\n"
- <> "\\end{signature}\n"
- ByteString.writeFile path
- (Text.encodeUtf8 (StrictText.pack source))
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- mounts <- exactFixtureMounts root
- workspace <- parseExactWorkspace bootstrap mounts relative
- let parsed = Parse.parsedWorkspaceRootModule workspace
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- unusedResolver
- Declaration.FreshValidation
- parsed
- [])
- Module.runTypedModule input >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactCompileFailed
- (Exact.ExactFixedSemanticCollision
- location key)))
- prefix -> do
- assertEqual "fixed collision line" 1 (locLine location)
- assertEqual "fixed collision key"
- (Semantic.SemanticExpressionFunction
- (Raw.TokenCons (Raw.Command "unions")
- (Raw.TokenCons Raw.InvisibleBraceL
- (Raw.HoleCons
- (Raw.TokenCons
- Raw.InvisibleBraceR Raw.End)))))
- key
- assertEqual "fixed collision commits no prefix"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Module.TypedModuleSucceeded{} ->
- assertFailure "fixed semantic declaration was accepted"
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("fixed semantic module did not open: "
- <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("unexpected fixed semantic failure: "
- <> show failure)
-
-rejectsFixedSemanticInductive :: Assertion
-rejectsFixedSemanticInductive =
- Temp.withSystemTempDirectory "felix-fixed-inductive" \root -> do
- let relative = "entry.tex"
- path = root Posix.</> relative
- source =
- "\\begin{inductive}\\label{source_pow}\n"
- <> " Define $\\pow{A}\\subseteq\\cumul{A}$ inductively as follows.\n"
- <> " \\begin{enumerate}\n"
- <> " \\item $A\\in\\pow{A}$.\n"
- <> " \\end{enumerate}\n"
- <> "\\end{inductive}\n"
- ByteString.writeFile path
- (Text.encodeUtf8 (StrictText.pack source))
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- mounts <- exactFixtureMounts root
- workspace <- parseExactWorkspace bootstrap mounts relative
- let parsed = Parse.parsedWorkspaceRootModule workspace
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- unusedResolver
- Declaration.FreshValidation
- parsed
- [])
- Module.runTypedModule input >>= \case
- Module.TypedModuleFailed
- (Module.TypedActionFailed
- (Module.TypedExactInductiveFailed
- (ExactInductive.ExactInductiveFixedSemanticCollision
- location key)))
- prefix -> do
- assertEqual "fixed inductive collision line"
- 1
- (locLine location)
- assertEqual "fixed inductive collision key"
- (Semantic.SemanticExpressionFunction
- (Raw.TokenCons (Raw.Command "pow")
- (Raw.TokenCons Raw.InvisibleBraceL
- (Raw.HoleCons
- (Raw.TokenCons
- Raw.InvisibleBraceR Raw.End)))))
- key
- assertEqual "fixed inductive collision commits no prefix"
- 0
- (length
- (Declaration.pendingModulePrefixBatches prefix))
- Module.TypedModuleSucceeded{} ->
- assertFailure "fixed semantic inductive was accepted"
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("fixed semantic inductive did not open: "
- <> show failure)
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("unexpected fixed inductive failure: "
- <> show failure)
-
-keepsExactSemanticsIndependentOfFixity :: Assertion
-keepsExactSemanticsIndependentOfFixity =
- Temp.withSystemTempDirectory "felix-exact-fixity" \root -> do
- let relative = "test/phase5/exact-producer.tex"
- path = root Posix.</> relative
- createDirectoryIfMissing True (Posix.takeDirectory path)
- original <- ByteString.readFile relative
- let changed =
- Text.encodeUtf8
- (StrictText.replace
- "infixl 2"
- "infixr 6"
- (Text.decodeUtf8 original))
- ByteString.writeFile path original
- first <- compileExactRootAt root relative
- ByteString.writeFile path changed
- second <- compileExactRootAt root relative
- let firstParsed = Parse.parsedWorkspaceRootModule (fst first)
- secondParsed = Parse.parsedWorkspaceRootModule (fst second)
- firstSealed = snd first
- secondSealed = snd second
- assertBool "fixity changes syntax identity"
- (Syntax.moduleSyntaxAssertedId
- (Parse.parsedModuleSyntaxInterface firstParsed)
- /= Syntax.moduleSyntaxAssertedId
- (Parse.parsedModuleSyntaxInterface secondParsed))
- assertBool "fixity changes parsed identity"
- (Parse.parsedModuleId firstParsed
- /= Parse.parsedModuleId secondParsed)
- assertEqual "fixity preserves semantic interface"
- (Module.sealedTypedModuleSemantic firstSealed)
- (Module.sealedTypedModuleSemantic secondSealed)
- assertEqual "fixity preserves semantic prefix"
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix firstSealed))
- (Declaration.pendingModulePrefixCurrent
- (Module.sealedTypedModulePrefix secondSealed))
-
-loadsCachedExactProducerForFreshImporter :: Assertion
-loadsCachedExactProducerForFreshImporter = do
- foundation <- expectRight Foundation.checkedFoundation
- Temp.withSystemTempDirectory "felix-exact-cache" \root -> do
- let path = root Posix.</> "store.sqlite"
- executable = root Posix.</> "vampire"
- writeAcceptedFixtureVampire executable
- (_startup, store) <-
- Store.openStore path (Identity.theoryId foundation)
- >>= expectRight
- let observer = Verification.verificationRequestObserver \_ordinal _request ->
- pure ()
- prover =
- Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit
- verify mode source =
- (checkResultWithStore
- store mode observer prover source)
- >>= expectRight
- producer <-
- verify Verification.FreshStoreValidation
- "test/phase5/exact-producer.tex"
- importer <-
- verify Verification.WarmStoreValidation
- "test/phase5/exact-importer.tex"
- assertTypedSuccess "fresh producer" producer
- assertTypedSuccess "warm producer/fresh importer" importer
- memo <- Store.newStoreMemo store
- prelude <-
- expectRight
- =<< Module.acquireFinalPreludeSession
- memo store foundation unusedResolver
- preludeVisits <- Store.storeMemoVisits memo
- repository <- getCurrentDirectory
- mounts <- exactFixtureMounts repository
- workspace <- parseFinalExactWorkspace
- prelude mounts "test/phase5/exact-importer.tex"
- let parsedModules =
- toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace)
- preludeSemantic =
- Module.sealedTypedModuleSemantic
- (Module.finalPreludeModule prelude)
- preludeId =
- Semantic.semanticInterfaceAssertedId preludeSemantic
- theory = Identity.theoryId foundation
- loadInstallation parsed direct = do
- key <- expectRight
- (Semantic.moduleArtifactKey
- (moduleName (Parse.parsedModuleAddress parsed))
- (Parse.parsedModuleId parsed)
- direct
- theory)
- loaded <- expectRight
- =<< Store.loadCachedModuleInstallation
- memo
- store
- key
- (Syntax.moduleSyntaxAssertedId
- (Parse.parsedModuleSyntaxInterface parsed))
- maybe
- (assertFailure "exact cached installation is absent"
- >> fail "unreachable")
- pure
- loaded
- environmentBindings installation =
- [ binding
- | delta <- Semantic.semanticInterfaceDeclarations
- (Store.cachedInstallationSemantic installation)
- , binding <- Semantic.semanticEnvironmentBindings
- (Semantic.declarationDeltaEnvironment delta)
- ]
- case parsedModules of
- [producerParsed, importerParsed] -> do
- producerInstallation <-
- loadInstallation producerParsed [preludeId]
- producerVisits <- Store.storeMemoVisits memo
- assertEqual "ordinary root adds one artifact validation"
- (Store.storeArtifactsValidated preludeVisits + 1)
- (Store.storeArtifactsValidated producerVisits)
- assertEqual "ordinary root reuses prelude syntax validation"
- (Store.storeSyntaxRowsValidated preludeVisits + 1)
- (Store.storeSyntaxRowsValidated producerVisits)
- assertEqual "ordinary root reuses prelude semantic validation"
- (Store.storeSemanticRowsValidated preludeVisits + 1)
- (Store.storeSemanticRowsValidated producerVisits)
- let producerSemanticId =
- Semantic.semanticInterfaceAssertedId
- (Store.cachedInstallationSemantic
- producerInstallation)
- importerInstallation <-
- loadInstallation
- importerParsed [preludeId, producerSemanticId]
- case ( environmentBindings producerInstallation
- , environmentBindings importerInstallation
- ) of
- (seedBinding : aliasBinding : _definitionBinding : [],
- [importerBinding]) -> do
- let seedTarget =
- Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget
- seedBinding)
- aliasTarget =
- Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget
- aliasBinding)
- importerTarget =
- Semantic.semanticGlobalTargetObject
- (Semantic.semanticGlobalBindingTarget
- importerBinding)
- assertEqual "cached importer reuses expanded content"
- aliasTarget importerTarget
- assertEqual "cached importer adds no object"
- []
- (Store.cachedInstallationObjects
- importerInstallation)
- expandedObject <-
- maybe
- (assertFailure
- "cached expanded object is absent"
- >> fail "unreachable")
- pure
- (find
- ((== aliasTarget)
- . Identity.assertedObjectId)
- (Store.cachedInstallationObjects
- producerInstallation))
- case Identity.assertedObjectContent expandedObject of
- Identity.TransparentObjectContent
- _identity _coreType body ->
- assertEqual
- "cached expansion retains the opaque seed"
- (Set.singleton seedTarget)
- (Core.canonicalTermGlobals body)
- content ->
- assertFailure
- ("cached expansion is not transparent: "
- <> show content)
- (producerBindings, importerBindings) ->
- assertFailure
- ("unexpected cached exact bindings: "
- <> show
- ( length producerBindings
- , length importerBindings
- ))
- modules ->
- assertFailure
- ("unexpected cached exact module count: "
- <> show (length modules))
- Store.closeStore store
-
-selectsConcurrentModuleFailureDeterministically :: Assertion
-selectsConcurrentModuleFailureDeterministically = do
- foundation <- expectRight Foundation.checkedFoundation
- Temp.withSystemTempDirectory "felix-concurrent-module-failure" \root -> do
- let executable = root Posix.</> "vampire"
- source = "test/phase7/concurrent-failure-root.tex"
- prover =
- Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit
- ignored =
- Verification.verificationRequestObserver
- (\_position _request -> pure ())
- select amount =
- Provers.selectEffectiveJobs
- (Provers.effectiveJobs amount)
- (fail "explicit jobs unexpectedly detected processors")
- reportEntry escape =
- ( Verification.reportedEscapeKind escape
- , locFile (Verification.reportedEscapeLocation escape)
- , locLine (Verification.reportedEscapeLocation escape)
- )
- inspect label expectedPositions
- (result, _slowReport, positions) = do
- case result of
- Verification.VerificationFailure report failed -> do
- assertEqual (label <> " selected earlier failure")
- "test/phase7/concurrent-earlier.tex"
- (locFile (Verification.failedVerificationLocation failed))
- assertEqual (label <> " admitted source prefix")
- [ ( Verification.ReportedSourceAxiom
- , "test/phase7/concurrent-earlier.tex"
- , 1
- )
- ]
- (reportEntry
- <$> Verification.verificationDirectEscapes report)
- other ->
- assertFailure
- (label <> " did not reject deterministically: "
- <> show other)
- assertEqual (label <> " executed only sibling obligations")
- expectedPositions
- (sort
- [ ( Provers.workPositionModuleOrdinal position
- , Provers.workPositionLocalRequestOrdinal position
- )
- | position <- positions
- ])
- runCase label jobsAmount = do
- let storePath = root Posix.</> (label <> ".sqlite")
- processLock = root Posix.</> (label <> ".process-lock")
- processStarted =
- root Posix.</> (label <> ".process-started")
- writeAcceptedFixtureVampire executable
- (_startup, store) <-
- Store.openStore storePath (Identity.theoryId foundation)
- >>= expectRight
- bracket (pure store) Store.closeStore \openStore -> do
- -- Seed only the final prelude. The unsupported ordinary
- -- module cannot publish a root.
- void
- (
- (checkFileWithStore
- openStore
- Verification.WarmStoreValidation
- ignored
- prover
- "test/phase3/typed-unsupported.tex")
- >>= expectRight)
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "while ! mkdir \"" <> processLock
- <> "\" 2>/dev/null; do sleep 0.01; done"
- , "trap 'rmdir \"" <> processLock
- <> "\"' EXIT"
- , ": > \"" <> processStarted <> "\""
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status CounterSatisfiable for concurrent-fixture'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- positionsRef <- newIORef []
- let observer =
- Verification.verificationRequestObserver
- (\position _request -> do
- atomicModifyIORef' positionsRef
- (\positions ->
- (position : positions, ()))
- when
- (jobsAmount > 1
- && Provers.workPositionModuleOrdinal
- position == 1)
- (waitForFileSignal
- "later module process"
- processStarted))
- jobs <- select jobsAmount
- (result, slowReport) <-
- (checkFileWithStoreAndJobs
- openStore
- Verification.WarmStoreValidation
- jobs
- observer
- prover
- source)
- >>= expectRight
- positions <- readIORef positionsRef
- pure (result, slowReport, positions)
- void $ runCase "parallel" 2
- >>= inspect "parallel" [(1, 1), (2, 1)]
- void $ runCase "sequential" 1
- >>= inspect "sequential" [(1, 1)]
-
-waitForFileSignal :: String -> FilePath -> Assertion
-waitForFileSignal label path = do
- guarded <- Timeout.timeout 10000000 loop
- case guarded of
- Just () ->
- pure ()
- Nothing ->
- assertFailure (label <> " was not observed")
- where
- loop = do
- exists <- doesFileExist path
- if exists
- then pure ()
- else do
- threadDelay 10000
- loop
-
-batchesStructureObligationsAtomically :: Assertion
-batchesStructureObligationsAtomically = do
- foundation <- expectRight Foundation.checkedFoundation
- Temp.withSystemTempDirectory "felix-structure-obligation-batch" \root -> do
- let storePath = root Posix.</> "store.sqlite"
- executable = root Posix.</> "vampire"
- unavailable = root Posix.</> "must-not-run-vampire"
- source = "test/phase7/structure-obligation-batch.tex"
- prover path =
- Provers.vampire
- path
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit
- select amount =
- Provers.selectEffectiveJobs
- (Provers.effectiveJobs amount)
- (fail "explicit jobs unexpectedly detected processors")
- run openStore jobs observer vampireCommand =
- (checkFileWithStoreAndJobs
- openStore
- Verification.WarmStoreValidation
- jobs
- observer
- vampireCommand
- source)
- >>= expectRight
- inspectFailure label positions (result, _slowReport) = do
- case result of
- Verification.VerificationFailure report failed -> do
- assertEqual (label <> " selects first consequence")
- (source, 12)
- ( locFile (Verification.failedVerificationLocation failed)
- , locLine (Verification.failedVerificationLocation failed)
- )
- assertEqual (label <> " retains preceding prefix")
- [(Verification.ReportedSourceAxiom, source, 1)]
- [ ( Verification.reportedEscapeKind escape
- , locFile (Verification.reportedEscapeLocation escape)
- , locLine (Verification.reportedEscapeLocation escape)
- )
- | escape <- Verification.verificationDirectEscapes report
- ]
- other ->
- assertFailure
- (label <> " did not reject its structure batch: "
- <> show other)
- assertEqual (label <> " assigns consecutive positions")
- [(1, 1), (1, 2)]
- (sort positions)
- writeAcceptedFixtureVampire executable
- (_startup, store) <-
- Store.openStore storePath (Identity.theoryId foundation)
- >>= expectRight
- bracket (pure store) Store.closeStore \openStore -> do
- let ignored =
- Verification.verificationRequestObserver
- (\_position _request -> pure ())
- -- Seed only the confined prelude so this fixture observes exactly
- -- the ordinary structure module's ready batch.
- void
- (
- (checkFileWithStore
- openStore
- Verification.WarmStoreValidation
- ignored
- (prover executable)
- "test/phase3/typed-unsupported.tex")
- >>= expectRight)
- parallelJobs <- select 2
- parallelPositions <- newIORef []
- firstStarted <- newEmptyTMVarIO
- secondStarted <- newEmptyTMVarIO
- releaseFirst <- newEmptyTMVarIO
- let laterCompleted = root Posix.</> "later-completed"
- writeLaterAcceptingVampire executable laterCompleted
- let parallelObserver =
- Verification.verificationRequestObserver \position _request -> do
- let ordinal =
- Provers.workPositionLocalRequestOrdinal position
- atomicModifyIORef' parallelPositions
- (\positions ->
- ( ( Provers.workPositionModuleOrdinal position
- , ordinal
- ) : positions
- , ()
- ))
- case ordinal of
- 1 -> do
- atomically (putTMVar firstStarted ())
- atomically (takeTMVar releaseFirst)
- 2 ->
- atomically (putTMVar secondStarted ())
- _ ->
- assertFailure
- ("unexpected structure request ordinal: "
- <> show ordinal)
- withAsync
- (run openStore parallelJobs parallelObserver
- (prover executable))
- \verification -> do
- void
- (awaitSignal "first structure request"
- (atomically (takeTMVar firstStarted)))
- void
- (awaitSignal "second structure request"
- (atomically (takeTMVar secondStarted)))
- -- Only the later member can reach the subprocess while
- -- the first observer is gated. Its completed signal
- -- therefore establishes reversed wall-clock completion.
- waitForFileSignal
- "later structure consequence"
- laterCompleted
- atomically (putTMVar releaseFirst ())
- parallelResult <- wait verification
- positions <- readIORef parallelPositions
- inspectFailure "parallel" positions parallelResult
-
- sequentialJobs <- select 1
- sequentialPositions <- newIORef []
- let sequentialCompleted = root Posix.</> "sequential-completed"
- writeRejectingVampire executable sequentialCompleted
- let sequentialObserver =
- Verification.verificationRequestObserver \position _request ->
- atomicModifyIORef' sequentialPositions
- (\positions ->
- ( ( Provers.workPositionModuleOrdinal position
- , Provers.workPositionLocalRequestOrdinal
- position
- ) : positions
- , ()
- ))
- sequentialResult <-
- run openStore sequentialJobs sequentialObserver
- (prover executable)
- sequentialObserved <- readIORef sequentialPositions
- inspectFailure "sequential"
- sequentialObserved sequentialResult
-
- -- A rejected sibling wrote neither validation nor a module root:
- -- the complete batch executes again, while the earlier source
- -- axiom remains the admitted prefix. A subsequent hit executes
- -- no request at all.
- writeAcceptedFixtureVampire executable
- acceptedPositions <- newIORef []
- let acceptedObserver =
- Verification.verificationRequestObserver \position _request ->
- modifyIORef' acceptedPositions
- (position :)
- (accepted, _acceptedSlowReport) <-
- run openStore parallelJobs acceptedObserver
- (prover executable)
- case accepted of
- Verification.VerificationCompleted report _presentation ->
- assertEqual "successful retry retains only source axiom"
- [Verification.ReportedSourceAxiom]
- (Verification.reportedEscapeKind
- <$> Verification.verificationDirectEscapes report)
- other ->
- assertFailure
- ("successful structure retry failed: " <> show other)
- acceptedObserved <- readIORef acceptedPositions
- assertEqual "successful retry executes the complete batch"
- 2
- (length acceptedObserved)
- let forbiddenObserver =
- Verification.verificationRequestObserver \position _request ->
- assertFailure
- ("warm structure batch invoked Vampire at "
- <> show position)
- (warm, _warmSlowReport) <-
- run openStore parallelJobs forbiddenObserver
- (prover unavailable)
- case warm of
- Verification.VerificationCompleted{} -> pure ()
- other ->
- assertFailure
- ("warm structure batch did not install: " <> show other)
- where
- awaitSignal label action = do
- result <- Timeout.timeout 10000000 action
- maybe
- (assertFailure (label <> " was not observed")
- >> fail "unreachable")
- pure
- result
-
- writeRejectingVampire executable completed = do
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , ": > \"" <> completed <> "\""
- , "printf '%s\\n' '% SZS status CounterSatisfiable for structure-batch-fixture'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
-
- writeLaterAcceptingVampire executable completed = do
- let firstProcess = completed <> ".first-process"
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , ": > \"" <> completed <> "\""
- , "if mkdir \"" <> firstProcess <> "\" 2>/dev/null; then"
- , " printf '%s\\n' '% SZS status Theorem for structure-batch-fixture'"
- , "else"
- , " printf '%s\\n' '% SZS status CounterSatisfiable for structure-batch-fixture'"
- , "fi"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
-
-speculatesDependentProofObligationsWithoutAdmittingAhead :: Assertion
-speculatesDependentProofObligationsWithoutAdmittingAhead = do
- foundation <- expectRight Foundation.checkedFoundation
- Temp.withSystemTempDirectory "felix-dependent-proof-chain" \root -> do
- let executable = root Posix.</> "vampire"
- unavailable = root Posix.</> "must-not-run-vampire"
- storePath = root Posix.</> "store.sqlite"
- source = "test/phase7/dependent-proof-chain.tex"
- prover path =
- Provers.vampire
- path
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit
- ignored =
- Verification.verificationRequestObserver
- (\_position _request -> pure ())
- writeAcceptedFixtureVampire executable
- (_startup, store) <-
- Store.openStore storePath (Identity.theoryId foundation)
- >>= expectRight
- bracket (pure store) Store.closeStore \openStore -> do
- -- Seed only the final prelude so the observed work belongs to the
- -- ordinary proof module.
- void
- (
- (checkFileWithStore
- openStore
- Verification.WarmStoreValidation
- ignored
- (prover executable)
- "test/phase3/typed-unsupported.tex")
- >>= expectRight)
- jobs <-
- Provers.selectEffectiveJobs
- (Provers.effectiveJobs 2)
- (fail "explicit jobs unexpectedly detected processors")
- firstStarted <- newEmptyTMVarIO
- secondStarted <- newEmptyTMVarIO
- releaseFirst <- newEmptyTMVarIO
- positionsRef <- newIORef []
- let observer =
- Verification.verificationRequestObserver \position _request -> do
- let ordinal =
- Provers.workPositionLocalRequestOrdinal position
- atomicModifyIORef' positionsRef
- (\positions ->
- ( ( Provers.workPositionModuleOrdinal position
- , ordinal
- ) : positions
- , ()
- ))
- case ordinal of
- 1 -> do
- atomically (putTMVar firstStarted ())
- atomically (takeTMVar releaseFirst)
- 2 -> atomically (putTMVar secondStarted ())
- _ ->
- assertFailure
- ("unexpected dependent proof request: "
- <> show ordinal)
- withAsync
- (
- (checkFileWithStoreAndJobs
- openStore
- Verification.WarmStoreValidation
- jobs
- observer
- (prover executable)
- source)
- >>= expectRight)
- \checking -> do
- void
- (awaitSignal "local subclaim request"
- (atomically (takeTMVar firstStarted)))
- -- The continuation is semantically dependent, but its
- -- already checked request may execute prospectively. It
- -- cannot be admitted until the local claim succeeds.
- void
- (awaitSignal "dependent continuation request"
- (atomically (takeTMVar secondStarted)))
- atomically (putTMVar releaseFirst ())
- (result, _slowReport) <- wait checking
- case result of
- Verification.VerificationCompleted report _presentation ->
- assertEqual "only the preceding axiom is reported"
- [Verification.ReportedSourceAxiom]
- (Verification.reportedEscapeKind
- <$> Verification.verificationDirectEscapes report)
- other ->
- assertFailure
- ("dependent proof module did not seal: "
- <> show other)
- positions <- readIORef positionsRef
- assertEqual "dependent requests retain source positions"
- [(1, 1), (1, 2)]
- (sort positions)
-
- let forbiddenObserver =
- Verification.verificationRequestObserver \position _request ->
- assertFailure
- ("warm dependent proof invoked Vampire at "
- <> show position)
- (warm, _warmSlowReport) <-
- (checkFileWithStoreAndJobs
- openStore
- Verification.WarmStoreValidation
- jobs
- forbiddenObserver
- (prover unavailable)
- source)
- >>= expectRight
- case warm of
- Verification.VerificationCompleted{} -> pure ()
- other ->
- assertFailure
- ("warm dependent proof did not install: " <> show other)
- where
- awaitSignal label action = do
- result <- Timeout.timeout 10000000 action
- maybe
- (assertFailure (label <> " was not observed")
- >> fail "unreachable")
- pure
- result
-
-schedulesDiamondAfterSealedImports :: Assertion
-schedulesDiamondAfterSealedImports = do
- foundation <- expectRight Foundation.checkedFoundation
- Temp.withSystemTempDirectory "felix-concurrent-diamond" \root -> do
- let storePath = root Posix.</> "store.sqlite"
- executable = root Posix.</> "vampire"
- unavailable = root Posix.</> "must-not-run-vampire"
- source = "test/phase7/diamond-root.tex"
- prover path =
- Provers.vampire
- path
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit
- ignored =
- Verification.verificationRequestObserver
- (\_position _request -> pure ())
- writeAcceptedFixtureVampire executable
- (_startup, store) <-
- Store.openStore storePath (Identity.theoryId foundation)
- >>= expectRight
- bracket (pure store) Store.closeStore \openStore -> do
- -- Acquire the final prelude before introducing scheduler gates.
- void
- (
- (checkFileWithStore
- openStore
- Verification.WarmStoreValidation
- ignored
- (prover executable)
- "test/phase3/typed-unsupported.tex")
- >>= expectRight)
- jobs <- Provers.selectEffectiveJobs
- (Provers.effectiveJobs 2)
- (fail "explicit jobs unexpectedly detected processors")
- baseStarted <- newEmptyTMVarIO
- branchStarted <- newTQueueIO
- rootStarted <- newEmptyTMVarIO
- releaseBase <- newTVarIO False
- releaseBranches <- newTVarIO False
- let awaitRelease released =
- atomically (readTVar released >>= check)
- observer =
- Verification.verificationRequestObserver
- (\position _request ->
- case Provers.workPositionModuleOrdinal position of
- 1 -> do
- atomically (putTMVar baseStarted ())
- awaitRelease releaseBase
- ordinal@2 -> do
- atomically
- (writeTQueue branchStarted ordinal)
- awaitRelease releaseBranches
- ordinal@3 -> do
- atomically
- (writeTQueue branchStarted ordinal)
- awaitRelease releaseBranches
- 4 ->
- atomically (putTMVar rootStarted ())
- _ ->
- pure ())
- verify vampireCommand requestObserver =
- (checkFileWithStoreAndJobs
- openStore
- Verification.WarmStoreValidation
- jobs
- requestObserver
- vampireCommand
- source)
- >>= expectRight
- await label action = do
- result <- Timeout.timeout 10000000 action
- maybe
- (assertFailure (label <> " was not observed")
- >> fail "unreachable")
- pure
- result
- withAsync (verify (prover executable) observer) \verification -> do
- void (await "base request" (atomically (takeTMVar baseStarted)))
- threadDelay 50000
- atomically (tryReadTQueue branchStarted) >>= \case
- Nothing -> pure ()
- Just ordinal ->
- assertFailure
- ("dependent module started before base seal: "
- <> show ordinal)
- atomically (writeTVar releaseBase True)
- firstBranch <- await "first branch"
- (atomically (readTQueue branchStarted))
- secondBranch <- await "second branch"
- (atomically (readTQueue branchStarted))
- assertEqual "both diamond branches became ready together"
- [2, 3]
- (sort [firstBranch, secondBranch])
- atomically (tryReadTMVar rootStarted) >>= \case
- Nothing -> pure ()
- Just () ->
- assertFailure
- "diamond root started before both branch seals"
- atomically (writeTVar releaseBranches True)
- void (await "diamond root" (atomically (takeTMVar rootStarted)))
- (coldResult, _coldSlowReport) <- wait verification
- case coldResult of
- Verification.VerificationCompleted{} -> pure ()
- other ->
- assertFailure
- ("cold diamond did not complete: " <> show other)
- let forbiddenObserver =
- Verification.verificationRequestObserver
- (\position _request ->
- assertFailure
- ("warm diamond invoked Vampire at "
- <> show position))
- (warmResult, _warmSlowReport) <-
- verify (prover unavailable) forbiddenObserver
- case warmResult of
- Verification.VerificationCompleted{} -> pure ()
- other ->
- assertFailure
- ("warm diamond did not install: " <> show other)
-
-reportsAdmittedSourceEscapes :: Assertion
-reportsAdmittedSourceEscapes = do
- foundation <- expectRight Foundation.checkedFoundation
- Temp.withSystemTempDirectory "felix-admitted-source-report" \root -> do
- let storePath = root Posix.</> "store.sqlite"
- executable = root Posix.</> "vampire"
- unavailable = root Posix.</> "must-not-run-vampire"
- observer =
- Verification.verificationRequestObserver \_ordinal _request -> pure ()
- prover path =
- Provers.vampire
- path
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit
- writeAcceptedFixtureVampire executable
- (_startup, store) <-
- Store.openStore storePath (Identity.theoryId foundation)
- >>= expectRight
- bracket (pure store) Store.closeStore \openStore -> do
- let verify mode vampirePath source =
- (checkFileWithStore
- openStore
- mode
- observer
- (prover vampirePath)
- source)
- >>= expectRight
- reportEntries =
- fmap
- (\escape ->
- ( Verification.reportedEscapeKind escape
- , locFile (Verification.reportedEscapeLocation escape)
- , locLine (Verification.reportedEscapeLocation escape)
- ))
- . Verification.verificationDirectEscapes
- expectedConsumer =
- [ ( Verification.ReportedSourceAxiom
- , "test/phase5/exact-escape-producer.tex"
- , 1
- )
- , ( Verification.ReportedOmitted
- , "test/phase5/exact-escape-producer.tex"
- , 9
- )
- , ( Verification.ReportedOmitted
- , "test/phase5/exact-escape-consumer.tex"
- , 35
- )
- ]
- (freshResult, _freshSlowReport) <-
- verify
- Verification.FreshStoreValidation
- executable
- "test/phase5/exact-escape-consumer.tex"
- freshReport <- case freshResult of
- Verification.CompletedWithExplicitGaps report _presentation -> pure report
- other ->
- assertFailure
- ("fresh escape report did not complete with gaps: "
- <> show other)
- >> fail "unreachable"
- assertEqual "fresh direct escapes"
- expectedConsumer
- (reportEntries freshReport)
- (warmResult, _warmSlowReport) <-
- verify
- Verification.WarmStoreValidation
- unavailable
- "test/phase5/exact-escape-consumer.tex"
- warmReport <- case warmResult of
- Verification.CompletedWithExplicitGaps report _presentation -> pure report
- other ->
- assertFailure
- ("warm escape report did not complete with gaps: "
- <> show other)
- >> fail "unreachable"
- assertEqual "warm report uses rebound current locations"
- freshReport warmReport
-
- void
- (verify
- Verification.FreshStoreValidation
- executable
- "test/phase5/exact-source-axiom.tex")
- (failedResult, _failedSlowReport) <-
- verify
- Verification.WarmStoreValidation
- unavailable
- "test/phase6/admitted-prefix-failure.tex"
- failedReport <- case failedResult of
- Verification.VerificationCheckingFailure report _failure -> pure report
- other ->
- assertFailure
- ("typed suffix failure was not report-bearing: "
- <> show other)
- >> fail "unreachable"
- assertEqual "failure report retains only admitted source prefix"
- (take 2 expectedConsumer
- <> [ ( Verification.ReportedOmitted
- , "test/phase6/admitted-prefix-failure.tex"
- , 7
- )
- ])
- (reportEntries failedReport)
-
-classifiesTypedVampireFailures :: Assertion
-classifiesTypedVampireFailures = do
- foundation <- expectRight Foundation.checkedFoundation
- Temp.withSystemTempDirectory "felix-typed-failure-classification" \root -> do
- let storePath = root Posix.</> "store.sqlite"
- executable = root Posix.</> "vampire"
- observer =
- Verification.verificationRequestObserver \_ordinal _request -> pure ()
- prover =
- Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit
- writeAcceptedFixtureVampire executable
- (_startup, store) <-
- Store.openStore storePath (Identity.theoryId foundation)
- >>= expectRight
- bracket (pure store) Store.closeStore \openStore -> do
- let verify source =
- (checkFileWithStore
- openStore
- Verification.WarmStoreValidation
- observer
- prover
- source)
- >>= expectRight
- writeProtocol lines = do
- writeFile executable
- (unlines (["#!/bin/sh", "cat >/dev/null"] <> lines))
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- expectTypedFailure classify = do
- (result, slowReport) <-
- verify "test/phase5/exact-runtime-failure.tex"
- case result of
- Verification.VerificationFailure report failed -> do
- assertEqual "typed failure has no direct escapes"
- []
- (Verification.verificationDirectEscapes report)
- assertEqual "typed failure retains source location"
- "test/phase5/exact-runtime-failure.tex"
- (locFile
- (Verification.failedVerificationLocation failed))
- classify
- (Verification.failedVerificationReason failed)
- (CommandLine.verificationCommandOutcome
- result slowReport)
- other ->
- assertFailure
- ("typed prover outcome was misclassified: "
- <> show other)
-
- -- Populate only the confined prelude. The selected ordinary
- -- module then remains a miss for each classified live failure.
- (_preludeResult, _preludeSlowReport) <-
- verify "test/phase3/typed-unsupported.tex"
-
- writeProtocol
- [ "printf '%s\\n' '% SZS status CounterSatisfiable for typed-failure'"
- , "exit 0"
- ]
- expectTypedFailure \reason outcome -> do
- case reason of
- Verification.CountermodelFailure{} -> pure ()
- other -> assertFailure ("expected countermodel: " <> show other)
- case outcome of
- CommandLine.VerificationRejected{} -> pure ()
- other -> assertFailure ("expected rejection: " <> show other)
-
- writeProtocol
- [ "printf '%s\\n' '% SZS status Timeout for typed-failure'"
- , "exit 0"
- ]
- expectTypedFailure \reason outcome -> do
- case reason of
- Verification.IndeterminateFailure{} -> pure ()
- other -> assertFailure ("expected indeterminate result: " <> show other)
- case outcome of
- CommandLine.VerificationRejected{} -> pure ()
- other -> assertFailure ("expected prover failure: " <> show other)
-
- writeProtocol
- [ "printf '%s\\n' '% SZS status Theorem for typed-failure'"
- , "exit 7"
- ]
- expectTypedFailure \reason outcome -> do
- case reason of
- Verification.ProtocolFailure{} -> pure ()
- other -> assertFailure ("expected protocol failure: " <> show other)
- case outcome of
- CommandLine.VerificationRejected{} -> pure ()
- other -> assertFailure ("expected prover failure: " <> show other)
-
- writeFile executable "not executable"
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable False permissions)
- expectTypedFailure \reason outcome -> do
- case reason of
- Verification.TransportFailure{} -> pure ()
- other -> assertFailure ("expected transport failure: " <> show other)
- case outcome of
- CommandLine.VerificationRejected{} -> pure ()
- other -> assertFailure ("expected prover failure: " <> show other)
-
-retainsExactPrefixBeforeFailure :: Assertion
-retainsExactPrefixBeforeFailure = do
- result <-
- withAcceptedFixtureVampire "felix-exact-failure" \prover ->
- (checkFileFresh
- prover
- "test/phase5/exact-failure.tex")
- case result of
- Right
- ( Verification.VerificationCheckingFailure _report
- (Verification.VerificationTypedModuleError
- source
- (Module.TypedActionFailed
- (Module.TypedExactCompileFailed
- (Exact.ExactGuardedOpaqueSignature location)))
- prefix)
- , _slowReport
- ) -> do
- assertEqual "failed exact source"
- "test/phase5/exact-failure.tex"
- (safeRelativePathFilePath
- (resolvedSourceRelativePath source))
- assertEqual "unsupported declaration line" 6 (locLine location)
- assertEqual "earlier exact declaration remains committed"
- 1
- (length (Declaration.pendingModulePrefixBatches prefix))
- Left err ->
- assertFailure ("unexpected exact failure: " <> show err)
- Right{} ->
- assertFailure "unsupported declaration was admitted"
-
- proofFailure <-
- withAcceptedFixtureVampire "felix-exact-proof-failure" \prover ->
- (checkFileFresh
- prover
- "test/phase5/exact-proof-failure.tex")
- case proofFailure of
- Right
- ( Verification.VerificationCheckingFailure _report
- (Verification.VerificationTypedModuleError
- _source
- (Module.TypedActionFailed
- (Module.TypedExactProofFailed
- (ExactProof.ExactProofGoalStatementMismatch
- location)))
- prefix)
- , _slowReport
- ) -> do
- assertEqual "mismatched assumption line" 10 (locLine location)
- assertEqual "failed proof publishes no theorem"
- 1
- (length (Declaration.pendingModulePrefixBatches prefix))
- Left err ->
- assertFailure
- ("unexpected exact proof failure: " <> show err)
- Right{} ->
- assertFailure "mismatched exact proof was admitted"
-
- unmatched <-
- withAcceptedFixtureVampire "felix-unmatched-proof" \prover ->
- (checkFileFresh
- prover
- "test/phase5/unmatched-proof.tex")
- case unmatched of
- Right
- ( Verification.VerificationCheckingFailure _report
- (Verification.VerificationTypedModuleError
- _source
- (Module.TypedActionFailed
- (Module.TypedUnmatchedProof location))
- prefix)
- , _slowReport
- ) -> do
- assertEqual "unmatched proof line" 1 (locLine location)
- assertEqual "unmatched proof publishes no declaration"
- 0
- (length (Declaration.pendingModulePrefixBatches prefix))
- Left err ->
- assertFailure
- ("unexpected unmatched-proof failure: " <> show err)
- Right{} ->
- assertFailure "unmatched proof was admitted"
-
- runtimeFailure <-
- Temp.withSystemTempDirectory "felix-runtime-proof-failure" \root -> do
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- repository <- getCurrentDirectory
- mounts <- exactFixtureMounts repository
- workspace <- parseExactWorkspace
- bootstrap mounts "test/phase5/exact-runtime-failure.tex"
- let executable = root Posix.</> "vampire"
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for located-proof'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- runs <- newIORef (0 :: Int)
- let resolver = Declaration.vampireResolver \prepared -> do
- runNumber <- readIORef runs
- modifyIORef' runs (+ 1)
- if runNumber == 0
- then
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
- else
- pure
- (Right
- (Provers.CounterSatisfiable
- "later exact obligation"))
- parsed = Parse.parsedWorkspaceRootModule workspace
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- resolver
- Declaration.FreshValidation
- parsed
- [])
- Module.runTypedModule input
- case runtimeFailure of
- Module.TypedModuleFailed
- failure@(Module.TypedDeclarationFailed
- (Declaration.ProofObligationFailedAt
- location
- Declaration.VampireObligationRejected{}))
- prefix -> do
- assertEqual "later rejected obligation line"
- 11
- (locLine location)
- assertEqual "typed failure retains obligation location"
- (Just location)
- (Module.typedModuleFailureLocation failure)
- assertEqual "runtime proof failure publishes no theorem"
- 1
- (length (Declaration.pendingModulePrefixBatches prefix))
- _result ->
- assertFailure "unexpected runtime proof failure"
-
-restoresCheckedSetInduction :: Assertion
-restoresCheckedSetInduction =
- Temp.withSystemTempDirectory "felix-checked-set-induction" \root -> do
- let executable = root Posix.</> "vampire"
- storePath = root Posix.</> "store.sqlite"
- writeAcceptedFixtureVampire executable
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation unusedResolver
- mounts <- exactFixtureMounts =<< getCurrentDirectory
-
- initialWorkspace <- parseExactWorkspace bootstrap mounts
- "test/phase5/exact-induction-initial.tex"
- initialObservations <- newIORef []
- initial <-
- sole "initial set-induction module"
- =<< compileParsedWorkspaceWithValidation
- foundation bootstrap
- (observingResolver executable initialObservations)
- Declaration.FreshValidation
- initialWorkspace
- [initialRequest] <-
- expectCount "initial set-induction request" 1
- =<< readIORef initialObservations
- assertEqual "initial induction retains header then hypothesis ordinals"
- [0, 1]
- (localReasoningLocalOrdinals initialRequest)
- let initialTarget =
- Core.CEq Core.TySet (Core.CBound 0) (Core.CBound 0)
- initialAntecedent =
- member (Core.CBound 1) (Core.CBound 0)
- initialHypothesis =
- Core.CForall Core.TySet
- (Core.CImp
- (member (Core.CBound 0) (Core.CBound 2))
- (Core.CImp
- (member (Core.CBound 0) (Core.CBound 1))
- (Core.CEq Core.TySet
- (Core.CBound 0)
- (Core.CBound 0))))
- assertEqual "initial induction child target"
- initialTarget
- (localReasoningTarget initialRequest)
- assertEqual "initial induction uses the complete guarded property"
- [initialAntecedent, initialHypothesis]
- (localReasoningLocalTerms initialRequest)
-
- nestedWorkspace <- parseExactWorkspace bootstrap mounts
- "test/phase5/exact-induction-nested.tex"
- nestedObservations <- newIORef []
- nested <-
- sole "nested set-induction module"
- =<< compileParsedWorkspaceWithValidation
- foundation bootstrap
- (observingResolver executable nestedObservations)
- Declaration.FreshValidation
- nestedWorkspace
- [nestedChild, nestedContinuation] <-
- expectCount "nested set-induction requests" 2
- =<< readIORef nestedObservations
- let x = Core.CBound 0
- a = Core.CBound 1
- y = Core.CBound 0
- xUnderY = Core.CBound 1
- aUnderY = Core.CBound 2
- guardAtX =
- andP
- (member x a)
- (notP (Core.CEq Core.TySet x a))
- guardAtY =
- andP
- (member y aUnderY)
- (notP (Core.CEq Core.TySet y aUnderY))
- nestedHypothesis =
- Core.CForall Core.TySet
- (Core.CImp
- (member y xUnderY)
- (Core.CImp
- guardAtY
- (Core.CEq Core.TySet y y)))
- nestedTarget = Core.CEq Core.TySet x x
- assertEqual
- "omitted leading induction retains its source binder and guard"
- ([0, 1], [nestedHypothesis, guardAtX], nestedTarget)
- ( localReasoningLocalOrdinals nestedChild
- , localReasoningLocalTerms nestedChild
- , localReasoningTarget nestedChild
- )
- case localReasoningLocalTerms nestedContinuation of
- [derived] -> do
- assertEqual "subproof continuation uses one derived local"
- [2] (localReasoningLocalOrdinals nestedContinuation)
- assertEqual "subproof closes the exact binder-level result"
- derived (localReasoningTarget nestedContinuation)
- locals ->
- assertFailure
- ("unexpected induction continuation locals: "
- <> show locals)
-
- formulaWorkspace <- parseExactWorkspace bootstrap mounts
- "test/phase5/exact-induction-formula-quantified.tex"
- formulaObservations <- newIORef []
- _formula <-
- sole "formula-quantified set-induction module"
- =<< compileParsedWorkspaceWithValidation
- foundation bootstrap
- (observingResolver executable formulaObservations)
- Declaration.FreshValidation
- formulaWorkspace
- [formulaChild, formulaContinuation] <-
- expectCount "formula-quantified set-induction requests" 2
- =<< readIORef formulaObservations
- assertEqual
- "formula-quantified omitted induction retains its written binder"
- (Core.CEq Core.TySet (Core.CBound 0) (Core.CBound 0))
- (localReasoningTarget formulaChild)
- assertEqual
- "formula-quantified continuation retains hypothesis and derived local"
- [0, 1]
- (localReasoningLocalOrdinals formulaContinuation)
-
- anchorWorkspace <- parseExactWorkspace bootstrap mounts
- "test/examples/no-reflexive-set.tex"
- anchorObservations <- newIORef []
- _anchor <-
- sole "omitted-focus set-induction module"
- =<< compileParsedWorkspaceWithValidation
- foundation bootstrap
- (observingResolver executable anchorObservations)
- Declaration.FreshValidation
- anchorWorkspace
- [anchorRequest] <-
- expectCount "omitted-focus set-induction request" 1
- =<< readIORef anchorObservations
- anchorLocal <-
- case localReasoningLocalTerms anchorRequest of
- [term] -> pure term
- terms ->
- assertFailure
- ("unexpected omitted-focus locals: " <> show terms)
- >> fail "unreachable"
- assertEqual "omitted focus retains its source binder in the child"
- ([0], Core.CForall Core.TySet
- (Core.CImp
- (member (Core.CBound 0) (Core.CBound 1))
- (notP (member (Core.CBound 0) (Core.CBound 0)))))
- ( localReasoningLocalOrdinals anchorRequest
- , anchorLocal
- )
-
- assertProofParityFailure
- foundation bootstrap mounts
- "test/phase5/exact-induction-ambiguous.tex"
- (\case
- ExactProof.ExactProofSetInductionFocusAmbiguous location ->
- locLine location == 5
- _failure -> False)
- assertProofParityFailure
- foundation bootstrap mounts
- "test/phase5/exact-induction-fixed.tex"
- (\case
- ExactProof.ExactProofSetInductionActiveBinderIneligible
- location (Raw.NamedVar "x") ->
- locLine location == 7
- _failure -> False)
-
- failedInput <-
- moduleInput
- foundation bootstrap initialWorkspace
- (Declaration.vampireResolver \_prepared ->
- pure
- (Right
- (Provers.CounterSatisfiable
- "focused induction child rejection")))
- Declaration.FreshValidation
- Module.runTypedModule failedInput >>= \case
- Module.TypedModuleFailed _failure prefix ->
- assertBool "failed induction child publishes no theorem"
- (null (Declaration.pendingModulePrefixBatches prefix))
- _result ->
- assertFailure "rejected induction child unexpectedly succeeded"
-
- bracket
- (snd <$> (Store.openStore storePath
- (Identity.theoryId foundation) >>= expectRight))
- Store.closeStore
- \store -> do
- expectRightIO
- (Store.writePendingModulePrefix store
- (Module.sealedTypedModulePrefix nested))
- let validation =
- Declaration.WarmValidation
- (Declaration.validationLookup
- (expectRightIO
- . Store.loadProofValidation store)
- (expectRightIO
- . Store.loadDeclarationValidation store))
- warmRuns <- newIORef (0 :: Int)
- warm <-
- sole "warm nested set-induction module"
- =<< compileParsedWorkspaceWithValidation
- foundation bootstrap
- (countingAcceptedResolver executable warmRuns)
- validation nestedWorkspace
- assertEqual "warm set induction skips Vampire"
- 0 =<< readIORef warmRuns
- assertEqual "fresh and warm induction proof validations"
- (proofValidations nested)
- (proofValidations warm)
- assertBool "initial induction publishes one theorem"
- (not
- (null
- (Declaration.pendingModulePrefixBatches
- (Module.sealedTypedModulePrefix initial))))
- where
- observingResolver executable observations =
- Declaration.vampireResolver \prepared -> do
- let problem = Provers.preparedTypedProverLogicalProblem prepared
- locals = Backend.typedProblemLocalPremises problem
- modifyIORef' observations
- (<> [ LocalReasoningObservation
- { localReasoningTarget =
- Backend.supportedPropositionTerm
- (Backend.typedProblemClaim problem)
- , localReasoningGlobalCount =
- Vector.length
- (Backend.typedProblemGlobalPremises problem)
- , localReasoningLocalOrdinals =
- Backend.localPremiseOrdinalValue
- . Backend.typedLocalPremiseOrdinal
- <$> Vector.toList locals
- , localReasoningLocalTerms =
- Backend.supportedPropositionTerm
- . Backend.typedLocalPremiseProposition
- <$> Vector.toList locals
- , localReasoningAuxiliaries =
- Backend.typedProblemAuxiliaryTag
- <$> Vector.toList
- (Backend.typedProblemAuxiliaries problem)
- }
- ])
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
-
- expectCount label expected values = do
- assertEqual label expected (length values)
- pure values
-
- member element set =
- Core.CApp
- (Core.CApp (Core.CIntrinsic Core.Member) element)
- set
-
- notP proposition = Core.CImp proposition Core.CFalsum
-
- andP left right = notP (Core.CImp left (notP right))
-
- moduleInput foundation bootstrap workspace resolver validation = do
- parsed <- sole "set-induction parsed module"
- (toList (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- expectRight
- (Module.typedModuleInput
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- resolver validation parsed [])
-
- proofValidations =
- concatMap Declaration.committedBatchProofValidations
- . Declaration.pendingModulePrefixBatches
- . Module.sealedTypedModulePrefix
-
-routesProductionVerification :: Assertion
-routesProductionVerification =
- Temp.withSystemTempDirectory "felix-production-route" \directory -> do
- let executable = directory Posix.</> "vampire"
- counter = directory Posix.</> "runs"
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' run >> " <> show counter
- , "printf '%s\\n' '% SZS status Theorem for production-route'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
- producer <- verifyFixture executable "test/phase3/typed-producer.tex"
- assertTypedSuccess "exact producer" producer
- selectedRuns <- runCount counter
- assertBool "ordinary roots construct the final prelude"
- (selectedRuns > 0)
- importer <- verifyFixture executable "test/phase3/typed-importer.tex"
- assertTypedSuccess "ordinary importer" importer
- assertBool "every root constructs the final prelude"
- . (> selectedRuns)
- =<< runCount counter
- where
- verifyFixture executable path =
- fst
- <$> (
- (checkFileFresh
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- path)
- >>= expectRight)
-
- runCount path =
- length . StrictText.lines . StrictText.pack <$> readFile path
-
-installsNonemptyImplicitPreludeEvidence :: Assertion
-installsNonemptyImplicitPreludeEvidence = do
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- closure <- expectRight
- (Identity.validateObjectClosure
- (Identity.theoryId foundation)
- [])
- proposition <- expectRight
- (Identity.validatePropositionContent closure Core.CFalsum)
- preludeDriver <- Declaration.runModuleDriver
- foundation
- preludeModuleName
- []
- unusedResolver
- Declaration.FreshValidation
- do
- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "nonempty-prelude") do
- candidate <- Declaration.reserveCandidate
- (Declaration.candidateSpec
- proposition
- Semantic.SearchEligible
- [Semantic.semanticName "prelude-fact"])
- Declaration.authorizeSourceAxiomCandidate candidate
- preludeResult <- expectRight preludeDriver
- (preludeSemantic, preludePrefix) <-
- case preludeResult of
- Declaration.DriverSucceeded _value semantic prefix _closure ->
- pure (semantic, prefix)
- _ ->
- assertFailure "nonempty prelude fixture did not seal"
- >> fail "unreachable"
- preludeFingerprint <-
- case concatMap
- Semantic.declarationDeltaFacts
- (Semantic.semanticInterfaceDeclarations preludeSemantic) of
- [occurrence] ->
- pure (Semantic.semanticFactFingerprint occurrence)
- facts ->
- assertFailure
- ("unexpected prelude fact count: "
- <> show (length facts))
- >> fail "unreachable"
- let preludeSyntax =
- Module.sealedTypedModuleSyntax
- (Module.bootstrapPreludeModule bootstrap)
- nonemptyPrelude <-
- Temp.withSystemTempDirectory "felix-nonempty-prelude" \directory -> do
- let path = directory Posix.</> "store.sqlite"
- theory = Identity.theoryId foundation
- parsed =
- Module.identifiedModuleParsed
- (Module.bootstrapPreludeInput bootstrap)
- (_startup, store) <-
- Store.openStore path theory >>= expectRight
- artifactKey <- expectRight
- (Semantic.moduleArtifactKey
- preludeModuleName
- (Parse.identifiedParsedModuleId parsed)
- []
- theory)
- let artifact =
- Semantic.moduleArtifactResult
- artifactKey
- (Syntax.moduleSyntaxAssertedId preludeSyntax)
- (Semantic.semanticInterfaceAssertedId
- preludeSemantic)
- _ <- expectRight
- =<< Store.writeSealedModule
- store
- preludePrefix
- [preludeSyntax]
- [preludeSemantic]
- artifact
- memo <- Store.newStoreMemo store
- loaded <- expectRight
- =<< Store.loadCachedModuleInstallation
- memo
- store
- artifactKey
- (Syntax.moduleSyntaxAssertedId preludeSyntax)
- installation <- maybe
- (assertFailure "nonempty prelude was not installed"
- >> fail "unreachable")
- pure
- loaded
- sealed <- expectRight
- (Module.cachedSealedTypedModule
- foundation
- []
- installation)
- Store.closeStore store
- pure sealed
-
- root <- getCurrentDirectory
- mounts <-
- expectRight
- =<< prepareSourceMounts
- [ (sourceMountId "project", root)
- , (sourceMountId "library", root Posix.</> "library")
- , (sourceMountId "debug", root Posix.</> "debug")
- ]
- request <- expectRight
- (searchedRoot "test/phase3/typed-producer.tex")
- workspace <-
- expectRight
- =<< Parse.parseSourceWorkspaceWithSyntaxInputs
- mounts
- request
- (const [preludeSyntax])
- let parsed = Parse.parsedWorkspaceRootModule workspace
- input <- expectRight
- (Module.typedModuleInput
- foundation
- (Module.fixtureFinalPreludeReadinessFromSealed nonemptyPrelude)
- unusedResolver
- Declaration.FreshValidation
- parsed
- [])
- ordinary <- Module.runTypedModule input >>= \case
- Module.TypedModuleSucceeded sealed -> pure sealed
- _ ->
- assertFailure "ordinary module rejected the nonempty prelude"
- >> fail "unreachable"
-
- consumerDigest <- expectRight
- (hashCanonicalFields
- "implicit-prelude-consumer"
- ["consumer"])
- consumerPath <- expectRight (safeRelativePath "consumer.tex")
- let consumerOwner =
- moduleNameFromParts
- (sourceNamespaceIdFromDigest consumerDigest)
- consumerPath
- consumed <- Declaration.runModuleDriver
- foundation
- consumerOwner
- [Semantic.semanticInterfaceAssertedId
- (Module.sealedTypedModuleSemantic ordinary)]
- unusedResolver
- Declaration.FreshValidation
- do
- Declaration.importSealedModuleDriver
- (Module.sealedTypedModuleEvidence ordinary)
- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "use-implicit-prelude") do
- candidate <- Declaration.reserveCandidate
- (Declaration.candidateSpec
- proposition
- Semantic.SearchIneligible
- [])
- Declaration.authorizeOmittedCandidate candidate do
- void
- (Declaration.useAuthorizedFact
- preludeFingerprint)
- Declaration.recordOmittedUse
- consumedResult <- expectRight consumed
- case consumedResult of
- Declaration.DriverSucceeded{} -> pure ()
- _ ->
- assertFailure
- "implicit prelude fact was not transitively visible"
-
-unusedResolver :: Declaration.VampireResolver
-unusedResolver =
- Declaration.vampireResolver \_prepared ->
- fail "empty bootstrap invoked Vampire"
-
-writeAcceptedFixtureVampire :: FilePath -> IO ()
-writeAcceptedFixtureVampire executable = do
- writeFile executable
- (unlines
- [ "#!/bin/sh"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for typed-fixture'"
- ])
- permissions <- getPermissions executable
- setPermissions executable
- (setOwnerExecutable True permissions)
-
-withAcceptedFixtureVampire
- :: String
- -> (Provers.Vampire -> IO value)
- -> IO value
-withAcceptedFixtureVampire label action =
- Temp.withSystemTempDirectory label \directory -> do
- let executable = directory Posix.</> "vampire"
- writeAcceptedFixtureVampire executable
- action
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
-
-finalPreludeResolver :: Declaration.VampireResolver
-finalPreludeResolver =
- Declaration.vampireResolver \prepared ->
- (Provers.runPreparedTypedProver
- (Provers.vampire
- "vampire"
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
-
-countingAcceptedResolver
- :: FilePath
- -> IORef Int
- -> Declaration.VampireResolver
-countingAcceptedResolver executable runs =
- Declaration.vampireResolver \prepared -> do
- modifyIORef' runs (+ 1)
- (Provers.runPreparedTypedProver
- (Provers.vampire
- executable
- Provers.defaultTimeLimit
- Provers.defaultMemoryLimit)
- prepared)
-
-prepareExactInductiveFixture
- :: FilePath
- -> IO
- (Either
- ExactInductive.ExactInductiveError
- ExactInductive.PreparedExactInductive)
-prepareExactInductiveFixture relative = do
- root <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts root
- workspace <- parseExactWorkspace bootstrap mounts relative
- parsed <-
- sole "exact inductive parsed module"
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- let identified = Module.identifiedPhysicalModule parsed
- owner = Module.identifiedModuleOwner identified
- parsedModule = Module.identifiedModuleParsed identified
- (blockIndex, block) <-
- sole "exact inductive block"
- [ (index, candidate)
- | (index, candidate@Raw.BlockInductive{}) <-
- zip [0..]
- (Parse.identifiedParsedModuleBlocks parsedModule)
- ]
- let entries =
- [ Parse.parsedSyntaxOccurrenceEntry occurrence
- | occurrence <-
- Parse.identifiedParsedModuleSyntaxOccurrences parsedModule
- , Parse.parsedSyntaxOccurrenceBlockIndex occurrence == blockIndex
- ]
- action
- :: Declaration.ModuleDriver Void
- (Either
- ExactInductive.ExactInductiveError
- ExactInductive.PreparedExactInductive)
- action =
- Declaration.runProspectiveLoweringDriver
- (ExactInductive.prepareExactInductive
- foundation
- block
- entries)
- result <-
- Declaration.runModuleDriver
- foundation
- owner
- []
- unusedResolver
- Declaration.FreshValidation
- action
- driver <- expectRight result
- case driver of
- Declaration.DriverSucceeded prepared _semantic _prefix _closure ->
- pure prepared
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("exact inductive preparation driver failed: "
- <> show failure)
- >> fail "unreachable"
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure
- ("exact inductive preparation driver did not seal: "
- <> show failure)
- >> fail "unreachable"
-
-prepareExactDatatypeFixture
- :: FilePath
- -> IO
- (Either
- ExactDatatype.ExactDatatypeError
- ( Foundation.CheckedFoundation
- , ModuleName
- , ExactDatatype.PreparedExactDatatype
- ))
-prepareExactDatatypeFixture relative = do
- root <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts root
- workspace <- parseExactWorkspace bootstrap mounts relative
- parsed <-
- sole "exact datatype parsed module"
- (toList
- (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- let identified = Module.identifiedPhysicalModule parsed
- owner = Module.identifiedModuleOwner identified
- parsedModule = Module.identifiedModuleParsed identified
- block <-
- sole "exact datatype block"
- (Parse.identifiedParsedModuleBlocks parsedModule)
- let occurrences =
- [ ( Parse.parsedSyntaxOccurrenceLocation occurrence
- , Parse.parsedSyntaxOccurrenceMarker occurrence
- , Parse.parsedSyntaxOccurrenceEntry occurrence
- )
- | occurrence <-
- Parse.identifiedParsedModuleSyntaxOccurrences parsedModule
- , Parse.parsedSyntaxOccurrenceBlockIndex occurrence == 0
- ]
- action
- :: Declaration.ModuleDriver Void
- (Either
- ExactDatatype.ExactDatatypeError
- ExactDatatype.PreparedExactDatatype)
- action =
- Declaration.runProspectiveLoweringDriver
- (ExactDatatype.prepareExactDatatype block occurrences)
- result <-
- Declaration.runModuleDriver
- foundation
- owner
- []
- unusedResolver
- Declaration.FreshValidation
- action
- driver <- expectRight result
- case driver of
- Declaration.DriverSucceeded prepared _semantic _prefix _closure ->
- pure
- ((\datatype -> (foundation, owner, datatype))
- <$> prepared)
- Declaration.DriverFailed failure _prefix ->
- assertFailure
- ("exact datatype preparation driver failed: "
- <> show failure)
- >> fail "unreachable"
- Declaration.DriverSealFailed failure _prefix ->
- assertFailure
- ("exact datatype preparation driver did not seal: "
- <> show failure)
- >> fail "unreachable"
-
-compileExactFixture
- :: FilePath
- -> IO
- ( Foundation.CheckedFoundation
- , Module.BootstrapPreludeFixture
- , Parse.ParsedSourceWorkspace
- , [Module.SealedTypedModule]
- )
-compileExactFixture relative = do
- root <- getCurrentDirectory
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts root
- workspace <- parseExactWorkspace bootstrap mounts relative
- sealed <- compileParsedWorkspace foundation bootstrap workspace
- pure (foundation, bootstrap, workspace, sealed)
-
-compileExactRootAt
- :: FilePath
- -> FilePath
- -> IO (Parse.ParsedSourceWorkspace, Module.SealedTypedModule)
-compileExactRootAt projectRoot relative = do
- foundation <- expectRight Foundation.checkedFoundation
- bootstrap <-
- expectRight
- =<< Module.buildBootstrapPreludeFixture
- foundation
- unusedResolver
- mounts <- exactFixtureMounts projectRoot
- workspace <- parseExactWorkspace bootstrap mounts relative
- sealed <- compileParsedWorkspace foundation bootstrap workspace
- rootModule <- sole "exact root module" (reverse sealed)
- pure (workspace, rootModule)
-
-exactFixtureMounts :: FilePath -> IO SourceMounts
-exactFixtureMounts projectRoot = do
- repository <- getCurrentDirectory
- expectRight
- =<< prepareSourceMounts
- [ (sourceMountId "project", projectRoot)
- , (sourceMountId "library", repository Posix.</> "library")
- , (sourceMountId "debug", repository Posix.</> "debug")
- ]
-
-parseExactWorkspace
- :: Module.BootstrapPreludeFixture
- -> SourceMounts
- -> FilePath
- -> IO Parse.ParsedSourceWorkspace
-parseExactWorkspace bootstrap mounts relative =
- parseExactWorkspaceWithPrelude
- (Module.bootstrapPreludeModule bootstrap)
- mounts
- relative
-
-parseFinalExactWorkspace
- :: Module.FinalPreludeSession
- -> SourceMounts
- -> FilePath
- -> IO Parse.ParsedSourceWorkspace
-parseFinalExactWorkspace prelude mounts relative =
- parseExactWorkspaceWithPrelude
- (Module.finalPreludeModule prelude)
- mounts
- relative
-
-parseExactWorkspaceWithPrelude
- :: Module.SealedTypedModule
- -> SourceMounts
- -> FilePath
- -> IO Parse.ParsedSourceWorkspace
-parseExactWorkspaceWithPrelude prelude mounts relative = do
- request <- expectRight (searchedRoot relative)
- let preludeSyntax =
- Module.sealedTypedModuleSyntax
- prelude
- expectRight
- =<< Parse.parseSourceWorkspaceWithSyntaxInputs
- mounts
- request
- (const [preludeSyntax])
-
-compileParsedWorkspace
- :: Foundation.CheckedFoundation
- -> Module.BootstrapPreludeFixture
- -> Parse.ParsedSourceWorkspace
- -> IO [Module.SealedTypedModule]
-compileParsedWorkspace foundation bootstrap workspace =
- compileParsedWorkspaceWithResolver
- foundation
- bootstrap
- unusedResolver
- workspace
-
-compileParsedWorkspaceWithResolver
- :: Foundation.CheckedFoundation
- -> Module.BootstrapPreludeFixture
- -> Declaration.VampireResolver
- -> Parse.ParsedSourceWorkspace
- -> IO [Module.SealedTypedModule]
-compileParsedWorkspaceWithResolver foundation bootstrap resolver workspace =
- compileParsedWorkspaceWithValidation
- foundation
- bootstrap
- resolver
- Declaration.FreshValidation
- workspace
-
-compileParsedWorkspaceWithValidation
- :: Foundation.CheckedFoundation
- -> Module.BootstrapPreludeFixture
- -> Declaration.VampireResolver
- -> Declaration.ValidationRun
- -> Parse.ParsedSourceWorkspace
- -> IO [Module.SealedTypedModule]
-compileParsedWorkspaceWithValidation
- foundation bootstrap resolver validation workspace =
- compileParsedWorkspaceWithReadiness
- foundation
- (Module.bootstrapPreludeReadiness bootstrap)
- resolver
- validation
- workspace
-
-compileFinalParsedWorkspaceWithResolver
- :: Foundation.CheckedFoundation
- -> Module.FinalPreludeSession
- -> Declaration.VampireResolver
- -> Parse.ParsedSourceWorkspace
- -> IO [Module.SealedTypedModule]
-compileFinalParsedWorkspaceWithResolver foundation prelude resolver workspace =
- compileParsedWorkspaceWithReadiness
- foundation
- (Module.finalPreludeReadiness prelude)
- resolver
- Declaration.FreshValidation
- workspace
-
-compileParsedWorkspaceWithReadiness
- :: Foundation.CheckedFoundation
- -> Module.FinalPreludeReadiness
- -> Declaration.VampireResolver
- -> Declaration.ValidationRun
- -> Parse.ParsedSourceWorkspace
- -> IO [Module.SealedTypedModule]
-compileParsedWorkspaceWithReadiness
- foundation readiness resolver validation workspace =
- snd
- <$> foldM
- compileOne
- (Map.empty, [])
- (toList (Parse.parsedWorkspaceImportedBeforeImporter workspace))
- where
- compileOne (admitted, ordered) parsed = do
- direct <-
- traverse
- (\address ->
- maybe
- (assertFailure
- ("missing exact direct module: " <> show address)
- >> fail "unreachable")
- pure
- (Map.lookup address admitted))
- (nubOrd
- (Parse.parsedImportedAddress
- <$> Parse.parsedModuleImports parsed))
- input <-
- expectRight
- (Module.typedModuleInput
- foundation
- readiness
- resolver
- validation
- parsed
- direct)
- sealed <-
- Module.runTypedModule input >>= \case
- Module.TypedModuleSucceeded module' -> pure module'
- Module.TypedModuleOpenFailed failure ->
- assertFailure
- ("exact module did not open: " <> show failure)
- >> fail "unreachable"
- Module.TypedModuleFailed failure _prefix ->
- assertFailure
- ("exact module did not seal: " <> show failure)
- >> fail "unreachable"
- pure
- ( Map.insert (Parse.parsedModuleAddress parsed) sealed admitted
- , ordered <> [sealed]
- )
-
-checkFileFresh
- :: Provers.Vampire
- -> FilePath
- -> IO
- (Either
- Verification.VerificationDriverError
- (Verification.VerificationResult, Provers.SlowAtpReport))
-checkFileFresh prover source = do
- plan <- Store.planStore Store.FreshTemporaryStore >>= expectRight
- Store.withStoreLease plan \lease -> do
- opened <- Verification.withVerificationSession lease
- (\session ->
- checkFileWithSession
- session
- Verification.FreshStoreValidation
- testSequentialJobs
- ignoredVerificationRequests
- prover
- source)
- case opened of
- Left failure ->
- assertFailure
- ("test verification session failed: " <> show failure)
- >> fail "unreachable"
- Right result -> pure result
-
-checkFileWithStore
- :: Store.Store
- -> Verification.StoreValidationMode
- -> Verification.VerificationRequestObserver
- -> Provers.Vampire
- -> FilePath
- -> IO
- (Either
- Verification.VerificationDriverError
- (Verification.VerificationResult, Provers.SlowAtpReport))
-checkFileWithStore store mode =
- checkFileWithStoreAndJobs store mode testSequentialJobs
-
-checkFileWithStoreAndJobs
- :: Store.Store
- -> Verification.StoreValidationMode
- -> Provers.EffectiveJobs
- -> Verification.VerificationRequestObserver
- -> Provers.Vampire
- -> FilePath
- -> IO
- (Either
- Verification.VerificationDriverError
- (Verification.VerificationResult, Provers.SlowAtpReport))
-checkFileWithStoreAndJobs store mode jobs observer prover source = do
- opened <- Verification.withVerificationSessionUsingStore store
- (\session ->
- checkFileWithSession session mode jobs observer prover source)
- case opened of
- Left failure ->
- assertFailure
- ("test verification session failed: " <> show failure)
- >> fail "unreachable"
- Right result -> pure result
-
-checkResultWithStore
- :: Store.Store
- -> Verification.StoreValidationMode
- -> Verification.VerificationRequestObserver
- -> Provers.Vampire
- -> FilePath
- -> IO
- (Either
- Verification.VerificationDriverError
- Verification.VerificationResult)
-checkResultWithStore store mode observer prover source =
- fmap (fmap fst)
- (checkFileWithStore store mode observer prover source)
-
-checkFileWithSession
- :: Verification.VerificationSession
- -> Verification.StoreValidationMode
- -> Provers.EffectiveJobs
- -> Verification.VerificationRequestObserver
- -> Provers.Vampire
- -> FilePath
- -> IO
- (Either
- Verification.VerificationDriverError
- (Verification.VerificationResult, Provers.SlowAtpReport))
-checkFileWithSession session mode jobs observer prover source =
- Workspace.prepareDefaultSourceGraph source >>= \case
- Left failure ->
- pure (Left (Verification.VerificationWorkspaceError failure))
- Right graph ->
- fmap
- (fmap
- (\outcome ->
- ( Verification.checkVerificationResult outcome
- , Verification.checkSlowAtpReport outcome
- )))
- (Verification.checkWorkspace
- session
- Verification.CheckRequest
- { Verification.checkSourceGraph = graph
- , Verification.checkStoreValidationMode = mode
- , Verification.checkEffectiveJobs = jobs
- , Verification.checkVampire = prover
- , Verification.checkRequestObserver = observer
- })
-
-ignoredVerificationRequests :: Verification.VerificationRequestObserver
-ignoredVerificationRequests =
- Verification.verificationRequestObserver
- (\_position _request -> pure ())
-
-testSequentialJobs :: Provers.EffectiveJobs
-testSequentialJobs =
- fromMaybe
- (impossible "one is a positive worker count")
- (Provers.effectiveJobs 1)
-
-assertTypedSuccess :: String -> Verification.VerificationResult -> Assertion
-assertTypedSuccess label = \case
- Verification.VerificationCompleted _report _presentation ->
- pure ()
- Verification.CompletedWithExplicitGaps _report _presentation ->
- assertFailure (label <> " completed with gaps")
- Verification.VerificationFailure _report failure ->
- assertFailure (label <> " failed: " <> show failure)
- Verification.VerificationCheckingFailure _report failure ->
- assertFailure (label <> " failed: " <> show failure)
-
-sole :: String -> [value] -> IO value
-sole label = \case
- [value] -> pure value
- values ->
- assertFailure
- (label <> ": expected one value, found " <> show (length values))
- >> fail "unreachable"
-
-expectRight :: Show error => Either error value -> IO value
-expectRight = \case
- Left err -> assertFailure (show err) >> fail "unreachable"
- Right value -> pure value
-
-expectRightIO :: Show error => IO (Either error value) -> IO value
-expectRightIO action =
- action >>= expectRight
-
-acquireFinalPreludeSession
- :: Store.Store
- -> Foundation.CheckedFoundation
- -> Declaration.VampireResolver
- -> IO
- (Either
- Module.FinalPreludeReadinessError
- Module.FinalPreludeSession)
-acquireFinalPreludeSession store foundation resolver = do
- memo <- Store.newStoreMemo store
- Module.acquireFinalPreludeSession
- memo store foundation resolver
diff --git a/source/Test/Unit/OutputPlan.hs b/source/Test/Unit/OutputPlan.hs
deleted file mode 100644
index 45658bf..0000000
--- a/source/Test/Unit/OutputPlan.hs
+++ /dev/null
@@ -1,236 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module Test.Unit.OutputPlan (unitTests) where
-
-import Base
-import Felix.OutputPlan qualified as Output
-import Felix.Source
-import Felix.Store qualified as Store
-
-import Control.Exception qualified as Exception
-import System.Directory qualified as Directory
-import System.Environment qualified as Environment
-import System.FilePath.Posix qualified as Posix
-import System.IO.Temp qualified as Temp
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "Verification output preflight"
- [ testCase "accepts absent and empty dump destinations"
- acceptsAbsentAndEmptyDumpDestinations
- , testCase "rejects a nonempty dump before store startup"
- rejectsNonemptyDumpBeforeStoreStartup
- , testCase "rejects persistent and fresh store collisions"
- rejectsStoreCollisions
- , testCase "reserves the store rollback journal"
- reservesRollbackJournal
- , testCase "rejects dump and HTML route collisions"
- rejectsDumpHtmlCollisions
- ]
-
-acceptsAbsentAndEmptyDumpDestinations :: Assertion
-acceptsAbsentAndEmptyDumpDestinations =
- Temp.withSystemTempDirectory "felix-output-dump" \root -> do
- let storeParent = root Posix.</> "store"
- storeFile = storeParent Posix.</> "store.sqlite"
- dump = root Posix.</> "dump"
- Directory.createDirectory storeParent
- plan <- expectRightIO
- (Store.planStore
- (Store.ExplicitStore storeFile))
- Store.withStoreLease plan \lease -> do
- absent <- Output.planVerificationOutputs
- (Store.storeLeasePath lease)
- (Just dump)
- Nothing
- plannedAbsent <- expectOutputRight absent
- assertEqual "absent dump path"
- (Just dump)
- (Output.dumpOutputPath
- <$> Output.verificationDumpOutput plannedAbsent)
-
- Directory.createDirectory dump
- emptyResult <- Output.planVerificationOutputs
- (Store.storeLeasePath lease)
- (Just dump)
- Nothing
- void (expectOutputRight emptyResult)
-
-rejectsNonemptyDumpBeforeStoreStartup :: Assertion
-rejectsNonemptyDumpBeforeStoreStartup =
- Temp.withSystemTempDirectory "felix-output-before-store" \root -> do
- let cacheRoot = root Posix.</> "cache"
- dump = root Posix.</> "dump"
- Directory.createDirectory cacheRoot
- Directory.createDirectory dump
- writeFile (dump Posix.</> "old.p") "stale"
- withEnvironment "XDG_CACHE_HOME" cacheRoot do
- plan <- expectRightIO
- (Store.planStore Store.DefaultStore)
- Store.withStoreLease plan \lease -> do
- result <- Output.planVerificationOutputs
- (Store.storeLeasePath lease)
- (Just dump)
- Nothing
- case result of
- Left Output.DumpDestinationNotEmpty{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected nonempty result: " <> show other)
- Right _ ->
- assertFailure "nonempty dump was accepted"
- assertBool "preflight did not create the default store"
- . not
- =<< Directory.doesPathExist
- (cacheRoot Posix.</> "felix")
-
-rejectsStoreCollisions :: Assertion
-rejectsStoreCollisions =
- Temp.withSystemTempDirectory "felix-output-store-collision" \root -> do
- let dump = root Posix.</> "dump"
- persistentStore = dump Posix.</> "store.sqlite"
- Directory.createDirectory dump
- persistentPlan <- expectRightIO
- (Store.planStore
- (Store.ExplicitStore persistentStore))
- Store.withStoreLease persistentPlan \lease -> do
- result <- Output.planVerificationOutputs
- (Store.storeLeasePath lease)
- (Just dump)
- Nothing
- expectCollision result
-
- freshPlan <- expectRightIO
- (Store.planStore Store.FreshTemporaryStore)
- Store.withStoreLease freshPlan \lease -> do
- let freshParent =
- Posix.takeDirectory
- (Store.storePathFilePath
- (Store.storeLeasePath lease))
- result <- Output.planVerificationOutputs
- (Store.storeLeasePath lease)
- (Just freshParent)
- Nothing
- expectCollision result
-
- relative <- expectRight (safeRelativePath "page.html")
- let htmlRoot = root Posix.</> "html"
- htmlStore = htmlRoot Posix.</> "page.html"
- Directory.createDirectory htmlRoot
- htmlPlan <- expectRightIO
- (Store.planStore
- (Store.ExplicitStore htmlStore))
- Store.withStoreLease htmlPlan \lease -> do
- result <- Output.planVerificationOutputs
- (Store.storeLeasePath lease)
- Nothing
- (Just (htmlRoot, [relative]))
- expectCollision result
-
-rejectsDumpHtmlCollisions :: Assertion
-rejectsDumpHtmlCollisions =
- Temp.withSystemTempDirectory "felix-output-cross-collision" \root -> do
- let storeParent = root Posix.</> "store"
- storeFile = storeParent Posix.</> "store.sqlite"
- htmlRoot = root Posix.</> "html"
- Directory.createDirectory storeParent
- Directory.createDirectory htmlRoot
- relative <- expectRight (safeRelativePath "nested/page.html")
- plan <- expectRightIO
- (Store.planStore
- (Store.ExplicitStore storeFile))
- Store.withStoreLease plan \lease -> do
- result <- Output.planVerificationOutputs
- (Store.storeLeasePath lease)
- (Just htmlRoot)
- (Just (htmlRoot, [relative]))
- expectCollision result
-
-reservesRollbackJournal :: Assertion
-reservesRollbackJournal =
- Temp.withSystemTempDirectory "felix-output-journal" \root -> do
- let storeParent = root Posix.</> "store"
- storeFile = storeParent Posix.</> "store.sqlite"
- journal = storeFile <> "-journal"
- Directory.createDirectory storeParent
- plan <- expectRightIO
- (Store.planStore
- (Store.ExplicitStore storeFile))
- Store.withStoreLease plan \lease -> do
- result <- Output.planVerificationOutputs
- (Store.storeLeasePath lease)
- (Just journal)
- Nothing
- case result of
- Left
- (Output.CollidingOutputNamespaces
- (Output.OutputNamespaceCollision
- Output.StoreJournalOutputNamespace
- reserved
- Output.DumpOutputNamespace
- requested :| [])) -> do
- assertEqual "reserved journal" journal reserved
- assertEqual "requested dump" journal requested
- Left other ->
- assertFailure
- ("unexpected journal collision: " <> show other)
- Right _ ->
- assertFailure "store rollback journal was not reserved"
-
-expectCollision
- :: Either Output.OutputPlanError Output.VerificationOutputPlan
- -> Assertion
-expectCollision = \case
- Left Output.CollidingOutputNamespaces{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected output-plan result: " <> show other)
- Right _ ->
- assertFailure "colliding output namespaces were accepted"
-
-expectOutputRight
- :: Either Output.OutputPlanError Output.VerificationOutputPlan
- -> IO Output.VerificationOutputPlan
-expectOutputRight = \case
- Left failure ->
- assertFailure (show failure) >> fail "unreachable"
- Right plan ->
- pure plan
-
-expectRight :: Show failure => Either failure value -> IO value
-expectRight = \case
- Left failure ->
- assertFailure (show failure) >> fail "unreachable"
- Right value ->
- pure value
-
-expectRightIO
- :: Show failure
- => IO (Either failure value)
- -> IO value
-expectRightIO action =
- expectRight =<< action
-
-withEnvironment
- :: String
- -> String
- -> IO value
- -> IO value
-withEnvironment name value action =
- Exception.bracket
- (Environment.lookupEnv name)
- restore
- \_previous -> do
- Environment.setEnv name value
- action
- where
- restore = \case
- Nothing ->
- Environment.unsetEnv name
- Just previous ->
- Environment.setEnv name previous
diff --git a/source/Test/Unit/Provers.hs b/source/Test/Unit/Provers.hs
deleted file mode 100644
index 0d0cf1b..0000000
--- a/source/Test/Unit/Provers.hs
+++ /dev/null
@@ -1,1159 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Unit.Provers (unitTests) where
-
-import Base hiding (Empty)
-import Checking.Backend.Problem
-import Checking.Core
-import Felix.Provers
-
-import Control.Concurrent
- ( newEmptyMVar
- , putMVar
- , takeMVar
- , threadDelay
- )
-import Control.Exception (bracket)
-import Control.Exception qualified as Exception
-import Control.Monad (when)
-import Data.IORef
- ( atomicModifyIORef'
- , newIORef
- , readIORef
- , writeIORef
- )
-import Data.Set qualified as Set
-import Data.Text qualified as Text
-import Data.Text.IO qualified as Text
-import Data.Vector qualified as Vector
-import Report.Location (Location(..))
-import System.Directory qualified as Directory
-import System.Exit (ExitCode(..))
-import System.FilePath.Posix ((</>))
-import System.Posix.Signals
- ( nullSignal
- , sigTERM
- , signalProcess
- )
-import System.Posix.Types (ProcessID)
-import System.Timeout qualified as Timeout
-import Test.Tasty
-import Test.Tasty.HUnit
-import Text.Read (readMaybe)
-import Text.Megaparsec (parseMaybe)
-import UnliftIO.Async (cancel, mapConcurrently, withAsync)
-import UnliftIO.Async qualified as Async
-
-unitTests :: TestTree
-unitTests =
- testGroup "Provers"
- [ vampireStatusParserTests
- , vampireClassifierTests
- , jobsSelectionTests
- , slowAtpReportTests
- , vampireExecutorTests
- , vampireProcessTests
- ]
-
-jobsSelectionTests :: TestTree
-jobsSelectionTests =
- testGroup "effective jobs"
- [ testCase "uses a positive override exactly" do
- detectorCalled <- newIORef False
- selected <- selectEffectiveJobs
- (effectiveJobs 3)
- (writeIORef detectorCalled True >> pure 99)
- selected `shouldBe` positiveJobs 3
- readIORef detectorCalled >>= (`shouldBe` False)
- , testCase "rounds automatic jobs to one third of detected processors" do
- for_
- [(8, 3), (16, 5), (24, 8), (32, 11)]
- \(detected, expected) -> do
- selected <- selectEffectiveJobs Nothing (pure detected)
- selected `shouldBe` positiveJobs expected
- , testCase "falls back to one after bad detection" do
- nonPositive <- selectEffectiveJobs Nothing (pure 0)
- nonPositive `shouldBe` positiveJobs 1
- failed <- selectEffectiveJobs Nothing
- (Exception.throwIO (userError "processor detection failed"))
- failed `shouldBe` positiveJobs 1
- ]
-
-slowAtpReportTests :: TestTree
-slowAtpReportTests =
- testGroup "slow ATP report"
- [ testCase "applies the threshold and retains the twelve slowest" do
- prepared <- preparedTypedTask 0
- let requestId =
- preparedVerificationRequestId
- (preparedTypedProverRequest prepared)
- task nanoseconds position =
- SlowAtpTask
- { slowAtpDuration =
- atpDurationFromNanoseconds nanoseconds
- , slowAtpOutcome = SlowAtpAccepted
- , slowAtpPosition = workPosition 1 position
- , slowAtpLocation = testLocation
- , slowAtpRequestId = requestId
- }
- report = slowAtpReportFromTasks
- ( task 4999999999 0
- : [ task (5000000000 + fromIntegral position) position
- | position <- [0..13]
- ]
- )
- slowAtpQualifyingTaskCount report `shouldBe` 14
- length (slowAtpTasks report) `shouldBe` 12
- slowAtpOmittedTaskCount report `shouldBe` 2
- atpDurationNanoseconds
- (slowAtpDuration
- (fromMaybe
- (error "slow report unexpectedly empty")
- (listToMaybe (slowAtpTasks report))))
- `shouldBe` 5000000013
- , testCase "keeps earlier source positions on equal durations" do
- prepared <- preparedTypedTask 0
- let requestId =
- preparedVerificationRequestId
- (preparedTypedProverRequest prepared)
- task position =
- SlowAtpTask
- { slowAtpDuration =
- atpDurationFromNanoseconds 5000000000
- , slowAtpOutcome = SlowAtpAccepted
- , slowAtpPosition = workPosition 1 position
- , slowAtpLocation = testLocation
- , slowAtpRequestId = requestId
- }
- report = slowAtpReportFromTasks (task <$> [1..13])
- (workPositionLocalRequestOrdinal . slowAtpPosition
- <$> slowAtpTasks report)
- `shouldBe` [1..12]
- ]
-
-vampireExecutorTests :: TestTree
-vampireExecutorTests =
- testGroup "bounded Vampire executor"
- [ testCase "records completed qualifying tasks with runtime context" do
- prepared <- preparedTypedTask 0
- clock <- scriptedClock [10, 5000000010]
- let position = workPosition 2 3
- withFakeVampire
- [ "cat >/dev/null"
- , "printf '%s\n' '% SZS status Theorem for fake'"
- ]
- \vampireCommand ->
- withVampireExecutorUsingClock
- clock
- (positiveJobs 1)
- vampireCommand
- (\_position _request -> pure ())
- \executor -> withVampireRequestOwner executor \owner -> do
- handle <- submitVampireRequest
- owner
- position
- testLocation
- (preparedTypedProverRequest prepared)
- awaitVampireRequest handle
- >>= assertAcceptedRequest prepared
- report <- vampireExecutorSlowAtpReport executor
- slowAtpQualifyingTaskCount report `shouldBe` 1
- case slowAtpTasks report of
- [task] -> do
- atpDurationNanoseconds
- (slowAtpDuration task)
- `shouldBe` 5000000000
- slowAtpOutcome task `shouldBe` SlowAtpAccepted
- slowAtpPosition task `shouldBe` position
- slowAtpLocation task `shouldBe` testLocation
- slowAtpRequestId task `shouldBe`
- preparedVerificationRequestId
- (preparedTypedProverRequest prepared)
- tasks ->
- assertFailure
- ("unexpected slow-task report: "
- <> show tasks)
- , testCase "does not report a cancelled partial task" do
- prepared <- preparedTypedTask 0
- clock <- scriptedClock [0, 6000000000]
- withProcessGroupFake
- defaultTimeLimit
- []
- \pidFile vampireCommand ->
- withVampireExecutorUsingClock
- clock
- (positiveJobs 1)
- vampireCommand
- (\_position _request -> pure ())
- \executor -> withVampireRequestOwner executor \owner -> do
- handle <- submitVampireRequest
- owner
- (workPosition 1 1)
- testLocation
- (preparedTypedProverRequest prepared)
- processIds <- waitForProcessIds pidFile
- cancelVampireRequest handle
- report <- vampireExecutorSlowAtpReport executor
- slowAtpQualifyingTaskCount report `shouldBe` 0
- assertBool "cancelled report is empty"
- (null (slowAtpTasks report))
- assertProcessesGone processIds
- , testCase "opaque handles complete out of submission order" do
- prepared <- preparedTypedTask 0
- firstStarted <- newEmptyMVar
- releaseFirst <- newEmptyMVar
- withFakeVampire
- [ "cat >/dev/null"
- , "printf '%s\n' '% SZS status Theorem for fake'"
- ]
- \vampireCommand ->
- withVampireExecutor
- (positiveJobs 2)
- vampireCommand
- (\position _request ->
- when
- (workPositionLocalRequestOrdinal position == 1)
- (putMVar firstStarted () >> takeMVar releaseFirst))
- \executor -> withVampireRequestOwner executor \owner -> do
- first <- submitVampireRequest
- owner
- (workPosition 1 1)
- testLocation
- (preparedTypedProverRequest prepared)
- takeMVar firstStarted
- second <- submitVampireRequest
- owner
- (workPosition 1 2)
- testLocation
- (preparedTypedProverRequest prepared)
- secondCompletion <- awaitVampireRequest second
- assertAcceptedRequest prepared secondCompletion
- putMVar releaseFirst ()
- firstCompletion <- awaitVampireRequest first
- assertAcceptedRequest prepared firstCompletion
- , testCase "validates request identity before a rejection" do
- submitted <- preparedTypedTask 0
- mismatched <- preparedTypedTask 1
- withFakeVampire
- [ "cat >/dev/null"
- , "printf '%s\n' '% SZS status CounterSatisfiable for fake'"
- ]
- \vampireCommand ->
- withVampireExecutor
- (positiveJobs 1)
- vampireCommand
- (\_position _request -> pure ())
- \executor -> withVampireRequestOwner executor \owner -> do
- handle <- submitVampireRequest
- owner
- (workPosition 1 1)
- testLocation
- (preparedTypedProverRequest submitted)
- outcome <- Exception.try
- (awaitPreparedVampireRequest
- (preparedTypedProverRequest mismatched)
- handle)
- case outcome of
- Left (failure :: VampireExecutorFault) ->
- assertBool
- "request mismatch is an integrity fault"
- ("wrong request id"
- `Text.isInfixOf`
- Text.pack (show failure))
- Right answer ->
- assertFailure
- ("mismatched rejection was accepted: "
- <> show answer)
- , testCase "runs requests through the bounded worker pool" do
- prepared <- preparedTypedTask 0
- withFakeVampire
- [ "previous=''"
- , "found=0"
- , "for argument in \"$@\"; do"
- , " if [ \"$previous\" = '--cores' ]; then"
- , " [ \"$argument\" = '2' ] || exit 17"
- , " found=1"
- , " fi"
- , " previous=$argument"
- , "done"
- , "[ \"$found\" = '1' ] || exit 18"
- , "cat >/dev/null"
- , "sleep 0.2"
- , "printf '%s\n' '% SZS status Theorem for fake'"
- ]
- \vampireCommand ->
- withVampireExecutor
- (positiveJobs 2)
- vampireCommand
- (\_position _request -> pure ())
- \executor -> withVampireRequestOwner executor \owner -> do
- answers <- mapConcurrently
- (\ordinal ->
- runPreparedTypedProverWithExecutor
- owner
- (workPosition 1 ordinal)
- testLocation
- prepared)
- [1..4]
- traverse_ assertProved answers
- , testCase "propagates observer failure to the submitter" do
- prepared <- preparedTypedTask 0
- withFakeVampire
- [ "cat >/dev/null"
- , "printf '%s\n' '% SZS status Theorem for fake'"
- ]
- \vampireCommand ->
- withVampireExecutor
- (positiveJobs 1)
- vampireCommand
- (\_position _request ->
- Exception.throwIO
- (userError "observer failed"))
- \executor -> withVampireRequestOwner executor \owner -> do
- result <- Exception.try
- (runPreparedTypedProverWithExecutor
- owner
- (workPosition 1 1)
- testLocation
- prepared)
- case result of
- Left (failure :: VampireExecutorFault) ->
- assertBool
- "global executor fault"
- ("observer failed"
- `Text.isInfixOf`
- Text.pack (show failure))
- Right answer ->
- assertFailure
- ("observer failure was lost: "
- <> show answer)
- , testCase "cancels queued and running jobs independently" do
- prepared <- preparedTypedTask 0
- withProcessGroupFake
- defaultTimeLimit
- []
- \pidFile vampireCommand ->
- withVampireExecutor
- (positiveJobs 1)
- vampireCommand
- (\_position _request -> pure ())
- \executor -> withVampireRequestOwner executor \owner ->
- withAsync
- (runPreparedTypedProverWithExecutor
- owner
- (workPosition 1 1)
- testLocation
- prepared)
- \running -> do
- processIds <- waitForProcessIds pidFile
- queuedSubmitted <- newEmptyMVar
- withAsync
- (do
- handle <- submitVampireRequest
- owner
- (workPosition 2 1)
- testLocation
- (preparedTypedProverRequest prepared)
- putMVar queuedSubmitted ()
- awaitPreparedVampireRequest
- (preparedTypedProverRequest prepared)
- handle)
- \queued -> do
- takeMVar queuedSubmitted
- cancel queued
- cancel running
- assertProcessesGone processIds
- , testCase "explicit cancellation completes queued and running handles" do
- prepared <- preparedTypedTask 0
- withProcessGroupFake
- defaultTimeLimit
- []
- \pidFile vampireCommand ->
- withVampireExecutor
- (positiveJobs 1)
- vampireCommand
- (\_position _request -> pure ())
- \executor -> withVampireRequestOwner executor \owner -> do
- running <- submitVampireRequest
- owner
- (workPosition 1 1)
- testLocation
- (preparedTypedProverRequest prepared)
- processIds <- waitForProcessIds pidFile
- queued <- submitVampireRequest
- owner
- (workPosition 1 2)
- testLocation
- (preparedTypedProverRequest prepared)
- cancelVampireRequest queued
- awaitVampireRequest queued
- >>= assertCancelled prepared
- cancelVampireRequest running
- awaitVampireRequest running
- >>= assertCancelled prepared
- assertProcessesGone processIds
- , testCase "structured shutdown wakes waiter and full-queue submitter" do
- prepared <- preparedTypedTask 0
- withProcessGroupFake
- defaultTimeLimit
- []
- \pidFile vampireCommand -> do
- (waiter, blockedSubmit, processIds) <-
- withVampireExecutor
- (positiveJobs 1)
- vampireCommand
- (\_position _request -> pure ())
- \executor ->
- withVampireRequestOwner executor \owner -> do
- running <- submitVampireRequest
- owner
- (workPosition 1 1)
- testLocation
- (preparedTypedProverRequest prepared)
- processIds <- waitForProcessIds pidFile
- _queuedOne <- submitVampireRequest
- owner
- (workPosition 1 2)
- testLocation
- (preparedTypedProverRequest prepared)
- _queuedTwo <- submitVampireRequest
- owner
- (workPosition 1 3)
- testLocation
- (preparedTypedProverRequest prepared)
- waiter <- Async.async
- (awaitVampireRequest running)
- submitStarted <- newEmptyMVar
- blockedSubmit <- Async.async do
- putMVar submitStarted ()
- submitVampireRequest
- owner
- (workPosition 1 4)
- testLocation
- (preparedTypedProverRequest prepared)
- takeMVar submitStarted
- pure (waiter, blockedSubmit, processIds)
- Async.waitCatch waiter >>= \case
- Right completion ->
- assertCancelled prepared completion
- Left failure ->
- assertFailure
- ("shutdown waiter failed: " <> show failure)
- Async.waitCatch blockedSubmit >>= \case
- Left failure ->
- assertBool
- "backpressured submit observes owner shutdown"
- ("VampireRequestOwnerClosed"
- `Text.isInfixOf`
- Text.pack (show failure))
- Right _handle ->
- assertFailure
- "backpressured submit survived structured shutdown"
- assertProcessesGone processIds
- , testCase "worker fault wakes a waiter and a full-queue submitter" do
- prepared <- preparedTypedTask 0
- observerEntered <- newEmptyMVar
- failObserver <- newEmptyMVar
- withFakeVampire
- [ "cat >/dev/null"
- , "printf '%s\n' '% SZS status Theorem for fake'"
- ]
- \vampireCommand ->
- withVampireExecutor
- (positiveJobs 1)
- vampireCommand
- (\position _request ->
- when
- (workPositionLocalRequestOrdinal position == 1)
- (putMVar observerEntered ()
- >> takeMVar failObserver
- >> Exception.throwIO
- (userError "fatal observer fault")))
- \executor -> withVampireRequestOwner executor \owner -> do
- first <- submitVampireRequest
- owner
- (workPosition 1 1)
- testLocation
- (preparedTypedProverRequest prepared)
- takeMVar observerEntered
- _second <- submitVampireRequest
- owner
- (workPosition 1 2)
- testLocation
- (preparedTypedProverRequest prepared)
- _third <- submitVampireRequest
- owner
- (workPosition 1 3)
- testLocation
- (preparedTypedProverRequest prepared)
- withAsync
- (submitVampireRequest
- owner
- (workPosition 1 4)
- testLocation
- (preparedTypedProverRequest prepared))
- \blockedSubmit -> do
- putMVar failObserver ()
- awaitFault (awaitVampireRequest first)
- Async.waitCatch blockedSubmit >>= \case
- Left failure ->
- assertExecutorFault failure
- Right _handle ->
- assertFailure
- "full-queue submission survived executor fault"
- , testCase "declared launch failure remains request-local" do
- prepared <- preparedTypedTask 0
- let missing = vampire
- "/definitely/missing/felix-vampire"
- defaultTimeLimit
- defaultMemoryLimit
- withVampireExecutor
- (positiveJobs 1)
- missing
- (\_position _request -> pure ())
- \executor -> withVampireRequestOwner executor \owner -> do
- handle <- submitVampireRequest
- owner
- (workPosition 1 1)
- testLocation
- (preparedTypedProverRequest prepared)
- completion <- awaitVampireRequest handle
- assertCompletionRequest prepared completion
- case vampireCompletionTerminal completion of
- VampireProcessFailed ProverLaunchFailed{} -> pure ()
- terminal ->
- assertFailure
- ("expected a local launch failure, got "
- <> show terminal)
- , testCase "protocol failure is distinct from ATP rejection" do
- prepared <- preparedTypedTask 0
- withFakeVampire
- [ "cat >/dev/null"
- , "printf '%s\n' 'completed without an SZS status'"
- ]
- \vampireCommand ->
- withVampireExecutor
- (positiveJobs 1)
- vampireCommand
- (\_position _request -> pure ())
- \executor -> withVampireRequestOwner executor \owner -> do
- handle <- submitVampireRequest
- owner
- (workPosition 1 1)
- testLocation
- (preparedTypedProverRequest prepared)
- completion <- awaitVampireRequest handle
- assertCompletionRequest prepared completion
- case vampireCompletionTerminal completion of
- VampireProtocolFailed{} -> pure ()
- terminal ->
- assertFailure
- ("expected a protocol terminal, got "
- <> show terminal)
- , testCase "completed rejection diagnostics are compact" do
- prepared <- preparedTypedTask 0
- let headMarker :: Text
- headMarker = "HEAD-MARKER"
- tailMarker :: Text
- tailMarker = "TAIL-MARKER"
- status :: Text
- status = "% SZS status CounterSatisfiable for fake"
- originalByteCount =
- Text.length headMarker
- + 1048576
- + Text.length tailMarker + 1
- + Text.length status + 1
- withFakeVampire
- [ "printf '%s' 'HEAD-MARKER'"
- , "head -c 1048576 /dev/zero"
- , "printf '%s\n' 'TAIL-MARKER'"
- , "printf '%s\n' '% SZS status CounterSatisfiable for fake'"
- ]
- \vampireCommand ->
- withVampireExecutor
- (positiveJobs 1)
- vampireCommand
- (\_position _request -> pure ())
- \executor -> withVampireRequestOwner executor \owner -> do
- handle <- submitVampireRequest
- owner
- (workPosition 1 1)
- testLocation
- (preparedTypedProverRequest prepared)
- completion <- awaitVampireRequest handle
- case renderVampireTerminalDiagnostic
- (vampireCompletionTerminal completion) of
- Just diagnostic -> do
- assertBool
- "retained diagnostic is bounded"
- (Text.length diagnostic < 70000)
- assertBool
- "truncation is reported"
- ("retained first and last 16 KiB"
- `Text.isInfixOf` diagnostic)
- assertBool
- "original byte count is reported"
- (("of "
- <> Text.pack
- (show originalByteCount)
- <> " bytes)")
- `Text.isInfixOf` diagnostic)
- assertBool
- "diagnostic head is retained"
- (headMarker `Text.isInfixOf` diagnostic)
- assertBool
- "diagnostic tail is retained"
- (tailMarker `Text.isInfixOf` diagnostic)
- Nothing ->
- assertFailure "expected a rejected terminal"
- ]
-
-positiveJobs :: Int -> EffectiveJobs
-positiveJobs amount =
- fromMaybe
- (error "test requested a non-positive job count")
- (effectiveJobs amount)
-
-scriptedClock :: [Word64] -> IO (IO Word64)
-scriptedClock ticks = do
- remaining <- newIORef ticks
- pure
- (atomicModifyIORef' remaining \case
- next : rest -> (rest, next)
- [] -> error "test monotonic clock exhausted")
-
-testLocation :: Location
-testLocation = Location maxBound
-
-vampireStatusParserTests :: TestTree
-vampireStatusParserTests =
- testGroup "Vampire status parser"
- [ testCase "parses canonical status lines" do
- parseMaybe
- vampireStatusParser
- "% SZS status ContradictoryAxioms for 2260"
- `shouldBe` Just StatusContradictoryAxioms
- , testCase "parses worker-prefixed status lines" do
- parseMaybe
- vampireStatusParser
- "% (2581105)SZS status Timeout for "
- `shouldBe` Just StatusTimeout
- , testCase "parses ResourceOut status" do
- parseMaybe
- vampireStatusParser
- "% SZS status ResourceOut for 2260"
- `shouldBe` Just StatusResourceOut
- , testCase "retains unsupported status values" do
- parseMaybe
- vampireStatusParser
- "% SZS status AlienResult for 2260"
- `shouldBe` Just (UnsupportedStatus "AlienResult")
- ]
-
-vampireClassifierTests :: TestTree
-vampireClassifierTests =
- testGroup "Vampire completed transcript classifier"
- [ testCase "maps each terminal status in both task modes" do
- classify DirectTask [StatusTheorem]
- `shouldBe` Right Proved
- classify DirectTask [StatusCounterSatisfiable]
- `shouldBe` Right Counterexample
- classify DirectTask [StatusContradictoryAxioms]
- `shouldBe` Right ContradictoryInput
- classify IndirectTask [StatusContradictoryAxioms]
- `shouldBe` Right Proved
- , testCase "maps every resource status to indeterminate" do
- for_ indeterminateStatuses \status ->
- classify DirectTask [status]
- `shouldBe` Right Indeterminate
- , testCase "lets a unique terminal outcome override resource statuses" do
- for_ indeterminateStatuses \status ->
- classify DirectTask [status, StatusTheorem]
- `shouldBe` Right Proved
- , testCase "accepts duplicate and equivalent terminal statuses" do
- classify DirectTask [StatusTheorem, StatusTheorem]
- `shouldBe` Right Proved
- classify
- IndirectTask
- [StatusTheorem, StatusContradictoryAxioms]
- `shouldBe` Right Proved
- , testCase "rejects every pair of different terminal outcomes" do
- for_ conflictingTerminalCases
- \(mode, statuses, outcomes) ->
- classify mode statuses
- `shouldBe`
- Left (ConflictingTerminalOutcomes outcomes)
- , testCase "is independent of status order" do
- for_ orderCases \(mode, statuses) ->
- classify mode statuses
- `shouldBe` classify mode (reverse statuses)
- , testCase "rejects unsupported status values" do
- classify
- DirectTask
- [StatusTheorem, UnsupportedStatus "AlienResult"]
- `shouldBe`
- Left
- (UnsupportedVampireStatuses
- (Set.singleton "AlienResult"))
- , testCase "rejects a successful exit without an outcome" do
- classify DirectTask []
- `shouldBe` Left MissingVampireOutcome
- , testCase "rejects every status after a nonzero exit" do
- classifyVampireProtocol
- DirectTask
- (ExitFailure 7)
- [StatusTheorem]
- `shouldBe`
- Left (UnsuccessfulVampireExit (ExitFailure 7))
- ]
-
-vampireProcessTests :: TestTree
-vampireProcessTests =
- testGroup "Vampire process boundary"
- [ testCase "classifies statuses from both completed streams" do
- answer <- runFakeVampire
- [ "printf '%s\\n' '% SZS status Timeout for fake'"
- , "printf '%s\\n' '% SZS status Theorem for fake' >&2"
- , "exit 0"
- ]
- assertProved answer
- , testCase "rejects a split-stream terminal conflict" do
- answer <- runFakeVampire
- [ "printf '%s\\n' '% SZS status Theorem for fake'"
- , "printf '%s\\n' '% SZS status CounterSatisfiable for fake' >&2"
- , "exit 0"
- ]
- assertProtocolError "ConflictingTerminalOutcomes" answer
- , testCase "rejects a theorem from a nonzero exit" do
- answer <- runFakeVampire
- [ "printf '%s\\n' '% SZS status Theorem for fake'"
- , "exit 7"
- ]
- assertProtocolError "ExitFailure 7" answer
- , testCase "rejects malformed UTF-8 output" do
- answer <- runFakeVampire
- [ "printf '\\377'"
- , "exit 0"
- ]
- case answer of
- Left
- (ProverOutputMalformedUtf8
- _
- ProverOutputStdout
- _) ->
- pure ()
- result ->
- assertFailure
- ("expected malformed stdout, got " <> show result)
- , testCase "returns a broken stdin pipe" do
- prepared <- preparedTypedTask 20000
- result <- withFakeVampire
- [ "exec 0<&-"
- , "sleep 1"
- ]
- \vampireCommand ->
- runPreparedTypedProver vampireCommand prepared
- case result of
- Left (ProverCommunicationFailed _ ProverStdin _) ->
- pure ()
- processResult ->
- assertFailure
- ("expected a communication failure, got "
- <> show processResult)
- , testCase "drains output while feeding prover input" do
- prepared <- preparedTypedTask 20000
- guardedAnswer <- Timeout.timeout
- 30000000
- (withFakeVampire
- [ "head -c 1048576 /dev/zero &"
- , "head -c 1048576 /dev/zero >&2 &"
- , "wait"
- , "printf '\\n'"
- , "printf '\\n' >&2"
- , "cat >/dev/null"
- , "printf '%s\\n' '% SZS status Theorem for fake'"
- , "exit 0"
- ]
- \vampireCommand -> do
- runPreparedTypedProver vampireCommand prepared)
- case guardedAnswer of
- Nothing ->
- assertFailure "prover communication did not finish"
- Just answer ->
- assertProved answer
- , testCase "reports signal termination separately" do
- prepared <- preparedTypedTask 0
- result <- withFakeVampire
- [ "kill -TERM $$"
- ]
- \vampireCommand ->
- runPreparedTypedProver vampireCommand prepared
- case result of
- Left
- (ProverTerminatedBySignal
- _
- signalNumber
- _) ->
- assertEqual
- "termination signal"
- (fromIntegral sigTERM)
- signalNumber
- processResult ->
- assertFailure
- ("expected signal termination, got "
- <> show processResult)
- , testCase "deadline terminates and reaps the process group" do
- prepared <- preparedTypedTask 0
- withProcessGroupFake
- (Seconds 0)
- []
- \pidFile vampireCommand -> do
- result <-
- runPreparedTypedProver vampireCommand prepared
- assertTimedOut result
- processIds <- readProcessIds pidFile
- assertProcessesGone processIds
- , testCase "output exhaustion terminates the process group" do
- prepared <- preparedTypedTask 0
- withProcessGroupFake
- defaultTimeLimit
- [ "head -c 33554432 /dev/zero"
- ]
- \pidFile vampireCommand -> do
- result <-
- runPreparedTypedProver vampireCommand prepared
- case result of
- Left
- (ProverOutputLimitExceeded
- _
- ProverOutputStdout
- _) ->
- pure ()
- processResult ->
- assertFailure
- ("expected stdout limit exhaustion, got "
- <> show processResult)
- processIds <- readProcessIds pidFile
- assertProcessesGone processIds
- , testCase "cancellation terminates and reaps the process group" do
- prepared <- preparedTypedTask 0
- withProcessGroupFake
- defaultTimeLimit
- []
- \pidFile vampireCommand ->
- withAsync
- (runPreparedTypedProver vampireCommand prepared)
- \worker -> do
- processIds <- waitForProcessIds pidFile
- cancel worker
- assertProcessesGone processIds
- ]
-
-classify
- :: VampireTaskMode
- -> [VampireStatus]
- -> Either VampireProtocolError CanonicalAtpOutcome
-classify mode =
- classifyVampireProtocol mode ExitSuccess
-
-indeterminateStatuses :: [VampireStatus]
-indeterminateStatuses =
- [ StatusTimeout
- , StatusResourceOut
- , StatusGaveUp
- , StatusUnknown
- ]
-
-conflictingTerminalCases
- :: [(VampireTaskMode, [VampireStatus], Set CanonicalAtpOutcome)]
-conflictingTerminalCases =
- [ ( DirectTask
- , [StatusTheorem, StatusCounterSatisfiable]
- , Set.fromList [Proved, Counterexample]
- )
- , ( DirectTask
- , [StatusTheorem, StatusContradictoryAxioms]
- , Set.fromList [Proved, ContradictoryInput]
- )
- , ( DirectTask
- , [StatusCounterSatisfiable, StatusContradictoryAxioms]
- , Set.fromList [Counterexample, ContradictoryInput]
- )
- , ( IndirectTask
- , [StatusTheorem, StatusCounterSatisfiable]
- , Set.fromList [Proved, Counterexample]
- )
- , ( IndirectTask
- , [StatusCounterSatisfiable, StatusContradictoryAxioms]
- , Set.fromList [Proved, Counterexample]
- )
- ]
-
-orderCases :: [(VampireTaskMode, [VampireStatus])]
-orderCases =
- [ (DirectTask, StatusTheorem : indeterminateStatuses)
- , (DirectTask, [StatusTheorem, StatusCounterSatisfiable])
- , (IndirectTask, [StatusTheorem, StatusContradictoryAxioms])
- , (DirectTask, [UnsupportedStatus "B", UnsupportedStatus "A"])
- ]
-
-assertProved
- :: Either ProverProcessError ProverAnswer
- -> Assertion
-assertProved = \case
- Right Yes ->
- pure ()
- answer ->
- assertFailure ("expected a proof, got " <> show answer)
-
-assertAcceptedRequest
- :: PreparedTypedProverTask ref local origin global
- -> VampireCompletion
- -> Assertion
-assertAcceptedRequest prepared completion = do
- assertCompletionRequest prepared completion
- case vampireCompletionTerminal completion of
- VampireAccepted -> pure ()
- terminal ->
- assertFailure ("expected an accepted terminal, got " <> show terminal)
-
-assertCompletionRequest
- :: PreparedTypedProverTask ref local origin global
- -> VampireCompletion
- -> Assertion
-assertCompletionRequest prepared completion =
- vampireCompletionRequestId completion
- `shouldBe`
- preparedVerificationRequestId
- (preparedTypedProverRequest prepared)
-
-assertCancelled
- :: PreparedTypedProverTask ref local origin global
- -> VampireCompletion
- -> Assertion
-assertCancelled prepared completion = do
- assertCompletionRequest prepared completion
- vampireCompletionTerminal completion `shouldBe` VampireCancelled
-
-awaitFault :: IO value -> Assertion
-awaitFault action = do
- result <- Exception.try action
- case result of
- Left failure -> assertExecutorFault failure
- Right _value -> assertFailure "expected a global executor fault"
-
-assertExecutorFault :: Exception.SomeException -> Assertion
-assertExecutorFault failure =
- case Exception.fromException failure :: Maybe VampireExecutorFault of
- Just _fault -> pure ()
- Nothing ->
- assertFailure
- ("expected VampireExecutorFault, got " <> show failure)
-
-assertProtocolError
- :: Text
- -> Either ProverProcessError ProverAnswer
- -> Assertion
-assertProtocolError expected = \case
- Right (Error _label diagnostic) ->
- assertBool
- ( "expected protocol error containing "
- <> show expected
- <> ", got "
- <> show diagnostic
- )
- (expected `Text.isInfixOf` diagnostic)
- answer ->
- assertFailure ("expected a protocol error, got " <> show answer)
-
-assertTimedOut
- :: Either ProverProcessError a
- -> Assertion
-assertTimedOut = \case
- Left ProverTimedOut{} ->
- pure ()
- result ->
- assertFailure ("expected prover timeout, got " <> showResult result)
- where
- showResult = \case
- Left err ->
- show err
- Right _ ->
- "successful process result"
-
-withProcessGroupFake
- :: TimeLimit
- -> [String]
- -> (FilePath -> Vampire -> IO a)
- -> IO a
-withProcessGroupFake timeLimit body action =
- withFakeVampireIn
- (\temp ->
- let pidFile = temp </> "process-ids"
- in [ "trap '' TERM"
- , "sleep 60 &"
- , "printf '%s %s\\n' \"$$\" \"$!\" > " <> pidFile
- ]
- <> body
- <> ["wait"])
- timeLimit
- \temp ->
- action (temp </> "process-ids")
-
-readProcessIds :: FilePath -> IO [ProcessID]
-readProcessIds path = do
- contents <- Text.readFile path
- case traverse
- (readMaybe . Text.unpack)
- (Text.words contents) of
- Just processIds@[_leader, _descendant] ->
- pure processIds
- _ ->
- assertFailure
- ("expected leader and descendant process ids, got "
- <> show contents)
-
-waitForProcessIds :: FilePath -> IO [ProcessID]
-waitForProcessIds path = do
- guarded <- Timeout.timeout 10000000 loop
- case guarded of
- Just processIds ->
- pure processIds
- Nothing ->
- assertFailure "fake prover did not publish its process ids"
- where
- loop = do
- exists <- Directory.doesFileExist path
- if exists
- then readProcessIds path
- else do
- threadDelay 10000
- loop
-
-assertProcessesGone :: [ProcessID] -> Assertion
-assertProcessesGone processIds = do
- guarded <- Timeout.timeout 10000000 loop
- case guarded of
- Just () ->
- pure ()
- Nothing ->
- assertFailure
- ("supervisor left processes running: "
- <> show processIds)
- where
- loop = do
- alive <- traverse processIsAlive processIds
- if or alive
- then do
- threadDelay 10000
- loop
- else pure ()
-
-processIsAlive :: ProcessID -> IO Bool
-processIsAlive processId =
- (signalProcess nullSignal processId >> pure True)
- `Exception.catch` \(err :: Exception.IOException) ->
- if isDoesNotExistError err
- then pure False
- else throwIO err
-
-runFakeVampire
- :: [String]
- -> IO (Either ProverProcessError ProverAnswer)
-runFakeVampire scriptLines =
- withFakeVampire
- (["cat >/dev/null"] <> scriptLines)
- \vampireCommand -> do
- prepared <- preparedTypedTask 0
- runPreparedTypedProver vampireCommand prepared
-
-withFakeVampire
- :: [String]
- -> (Vampire -> IO a)
- -> IO a
-withFakeVampire scriptLines action =
- withFakeVampireIn
- (const scriptLines)
- defaultTimeLimit
- (const action)
-
-withFakeVampireIn
- :: (FilePath -> [String])
- -> TimeLimit
- -> (FilePath -> Vampire -> IO a)
- -> IO a
-withFakeVampireIn makeScript timeLimit action =
- withTemporaryDirectory "felix-fake-vampire" \temp -> do
- let executablePath = temp </> "vampire"
- writeFile executablePath
- (unlines
- ( [ "#!/bin/sh"
- ]
- <> makeScript temp
- ))
- permissions <- Directory.getPermissions executablePath
- Directory.setPermissions executablePath
- (Directory.setOwnerExecutable True permissions)
- action
- temp
- (vampire
- executablePath
- timeLimit
- defaultMemoryLimit)
-
-withTemporaryDirectory :: String -> (FilePath -> IO a) -> IO a
-withTemporaryDirectory template =
- bracket create Directory.removePathForcibly
- where
- create = do
- systemTemp <- Directory.getTemporaryDirectory
- (path, handle) <- openTempFile systemTemp template
- hClose handle
- Directory.removeFile path
- Directory.createDirectory path
- pure path
-
-shouldBe :: (Eq a, Show a, HasCallStack) => a -> a -> Assertion
-shouldBe =
- flip (assertEqual "")
-
-preparedTypedTask
- :: Int
- -> IO (PreparedTypedProverTask Int Void Void Void)
-preparedTypedTask factCount = do
- checked <- expectRight
- (checkScopedCanonicalCore
- (const Nothing)
- []
- propositionTerm)
- proposition <- expectRight
- (supportedProposition Vector.empty checked)
- capability <- expectRight
- (classifySupportedProposition (const Nothing) proposition)
- let facts =
- Vector.generate
- factCount
- (\reference ->
- typedBackendFact reference proposition capability)
- problem <- expectRight
- (planTypedProblem
- (const Nothing)
- facts
- proposition
- []
- []
- FirstOrderLocals
- ExplicitHigherOrderJustification)
- expectRight (prepareTypedProverTask DirectTask problem)
- where
- propositionTerm =
- CEq TySet
- (CIntrinsic Empty)
- (CIntrinsic Empty)
-
-expectRight :: Show error => Either error value -> IO value
-expectRight = \case
- Left failure ->
- assertFailure (show failure) >> fail "unreachable"
- Right value ->
- pure value
diff --git a/source/Test/Unit/Semantic.hs b/source/Test/Unit/Semantic.hs
deleted file mode 100644
index 160735c..0000000
--- a/source/Test/Unit/Semantic.hs
+++ /dev/null
@@ -1,437 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module Test.Unit.Semantic (unitTests) where
-
-import Base
-import Checking.Authority qualified as Authority
-import Checking.Core qualified as Core
-import Checking.Foundation qualified as Foundation
-import Checking.Identity qualified as Identity
-import Checking.Semantic qualified as Semantic
-import Felix.Cache.Codec
-import Felix.Math.Codec
-import Felix.Module
-import Felix.Parsed.Identity
-import Felix.Source
-import Felix.Source.Content
-import Syntax.Interface qualified as Syntax
-import Syntax.Abstract qualified as Raw
-
-import Data.ByteString (ByteString)
-import Data.List qualified as List
-import Data.Map.Strict qualified as Map
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "Semantic interfaces"
- [ testCase "separates syntax and semantic Merkle identities"
- separatesSyntaxAndSemantics
- , testCase "round-trips closed semantic declaration state"
- roundTripsSemanticState
- , testCase "round-trips exact semantic global keys"
- roundTripsSemanticGlobalKeys
- , testCase "round-trips canonical structure descriptors"
- roundTripsStructureDescriptors
- , testCase "keys exact proof and module inputs"
- keysExactInputs
- ]
-
-separatesSyntaxAndSemantics :: Assertion
-separatesSyntaxAndSemantics = do
- fixture <- makeFixture
- firstSyntax <- makeSyntax "first"
- secondSyntax <- makeSyntax "second"
- assertBool
- "notation changes syntax identity"
- ( Syntax.moduleSyntaxAssertedId firstSyntax
- /= Syntax.moduleSyntaxAssertedId secondSyntax
- )
- assertEqual
- "notation does not enter semantic prefix identity"
- (fixtureNextPrefix fixture)
- (Semantic.nextPrefixContextId
- (fixtureInitialPrefix fixture)
- (fixtureDelta fixture))
-
-roundTripsSemanticState :: Assertion
-roundTripsSemanticState = do
- fixture <- makeFixture
- assertEqual
- "semantic interface cache round trip"
- (Right (fixtureInterface fixture))
- (decodeCache
- Semantic.getSemanticInterfaceCache
- (encodeCache
- (Semantic.putSemanticInterfaceCache
- (fixtureInterface fixture))))
- assertEqual
- "walking-subset environment delta round trip"
- (Right Semantic.emptySemanticEnvironmentDelta)
- (decodeCache
- Semantic.getSemanticEnvironmentDeltaCache
- (encodeCache
- (Semantic.putSemanticEnvironmentDeltaCache
- Semantic.emptySemanticEnvironmentDelta)))
-
-roundTripsSemanticGlobalKeys :: Assertion
-roundTripsSemanticGlobalKeys = do
- fixture <- makeFixture
- let unary = Raw.HoleCons (Raw.TokenCons (Raw.Command "f") Raw.End)
- plural = Raw.HoleCons (Raw.TokenCons (Raw.Word "things") Raw.End)
- keys =
- [ Semantic.SemanticLeftAdjective unary
- , Semantic.SemanticRightAdjective unary
- , Semantic.SemanticFunctionPhrase unary plural
- , Semantic.SemanticNoun unary plural
- , Semantic.SemanticVerb unary plural
- , Semantic.SemanticRelation
- (Raw.Command "rel")
- (Raw.ParameterArity 2)
- , Semantic.SemanticExpressionFunction unary
- , Semantic.SemanticPrefixPredicate "Pred" 3
- ]
- target =
- Identity.intrinsicObjectId
- (fixtureTheory fixture)
- Core.Empty
- Core.TySet
- bindings =
- List.sortOn Semantic.semanticGlobalBindingKey
- ( case keys of
- [] -> []
- first : rest ->
- Semantic.semanticGlobalBinding
- first
- (Semantic.ContextualTransparentExpansion
- target
- (Map.singleton
- (Raw.StructSymbol "operation")
- target))
- : [ Semantic.semanticGlobalBinding
- key
- (Semantic.GlobalReference target)
- | key <- rest
- ]
- )
- delta <- expectRight (Semantic.semanticEnvironmentDelta bindings)
- assertEqual "binding cache round trip"
- (Right delta)
- (decodeCache
- Semantic.getSemanticEnvironmentDeltaCache
- (encodeCache
- (Semantic.putSemanticEnvironmentDeltaCache delta)))
- case bindings of
- first : second : _ -> do
- assertEqual "rejects noncanonical order"
- (Left Semantic.NonCanonicalSemanticGlobalBindingOrder)
- (Semantic.semanticEnvironmentDelta
- (second : first : drop 2 bindings))
- assertEqual "rejects duplicate key"
- (Left
- (Semantic.DuplicateSemanticGlobalKey
- (Semantic.semanticGlobalBindingKey first)))
- (Semantic.semanticEnvironmentDelta [first, first])
- _ -> assertFailure "semantic key fixture is unexpectedly empty"
-
-roundTripsStructureDescriptors :: Assertion
-roundTripsStructureDescriptors = do
- fixture <- makeFixture
- let structurePhrase marker word =
- Semantic.semanticStructurePhrase
- (Raw.LexicalItemSgPl
- (Raw.SgPl
- (Raw.TokenCons (Raw.Word word) Raw.End)
- (Raw.TokenCons (Raw.Word (word <> "s")) Raw.End))
- marker)
- base = structurePhrase "onesorted_structure" "base"
- child = structurePhrase "ordered_structure" "ordered"
- object =
- Identity.intrinsicObjectId
- (fixtureTheory fixture)
- Core.Empty
- Core.TySet
- operation =
- Semantic.semanticStructureOperation
- (Raw.StructSymbol "carrier")
- object
- descriptor <- expectRight
- (Semantic.semanticStructureDescriptor
- child
- (Just object)
- [base]
- [operation])
- delta <- expectRight
- (Semantic.semanticEnvironmentWithStructures [] [descriptor])
- assertEqual
- "structure environment cache round trip"
- (Right delta)
- (decodeCache
- Semantic.getSemanticEnvironmentDeltaCache
- (encodeCache
- (Semantic.putSemanticEnvironmentDeltaCache delta)))
- assertEqual
- "duplicate local operation is rejected"
- (Left
- (Semantic.DuplicateSemanticStructureOperation
- (Raw.StructSymbol "carrier")))
- (Semantic.semanticStructureDescriptor
- child
- (Just object)
- [base]
- [operation, operation])
-
-keysExactInputs :: Assertion
-keysExactInputs = do
- fixture <- makeFixture
- let authority =
- Authority.factAuthority
- (fixtureTheorem fixture)
- Authority.cleanAuthoritySafety
- certificate <- expectRight
- (Authority.validationCertificate
- authority
- (Authority.CheckedSourceProof []))
- let theorem =
- Identity.theoremId
- (fixtureTheorem fixture)
- firstProof =
- Semantic.proofValidationKey
- theorem
- (Semantic.proofSyntaxId "proof-a")
- (fixtureInitialPrefix fixture)
- secondProof =
- Semantic.proofValidationKey
- theorem
- (Semantic.proofSyntaxId "proof-b")
- (fixtureInitialPrefix fixture)
- laterContext =
- Semantic.proofValidationKey
- theorem
- (Semantic.proofSyntaxId "proof-a")
- (fixtureNextPrefix fixture)
- assertBool
- "proof syntax is an exact validation input"
- (firstProof /= secondProof)
- assertBool
- "semantic predecessor is an exact validation input"
- (firstProof /= laterContext)
- let proofRecord =
- Semantic.proofValidationRecord
- firstProof certificate
- declarationKey =
- Semantic.declarationValidationKey
- (Semantic.declarationSyntaxId "declaration")
- (fixtureInitialPrefix fixture)
- []
- [theorem, theorem]
- declarationRecord =
- Semantic.declarationValidationRecord
- declarationKey
- [certificate, certificate]
- assertEqual
- "proof validation record cache round trip"
- (Right proofRecord)
- (decodeCache
- Semantic.getProofValidationRecordCache
- (encodeCache
- (Semantic.putProofValidationRecordCache
- proofRecord)))
- assertEqual
- "ordered declaration certificates retain repetitions"
- (Right declarationRecord)
- (decodeCache
- Semantic.getDeclarationValidationRecordCache
- (encodeCache
- (Semantic.putDeclarationValidationRecordCache
- declarationRecord)))
- firstParsedKey <- expectRight
- (parsedModuleKey
- (fixtureSourceContentId "source-a")
- Syntax.baseSyntaxInterfaceId
- [])
- secondParsedKey <- expectRight
- (parsedModuleKey
- (fixtureSourceContentId "source-b")
- Syntax.baseSyntaxInterfaceId
- [])
- directSyntax <- makeSyntax "direct"
- let directSyntaxId =
- Syntax.moduleSyntaxAssertedId directSyntax
- assertEqual
- "parsed identity rejects duplicate direct syntax"
- (Left
- (DuplicateParsedDirectSyntaxInput
- directSyntaxId))
- (parsedModuleKey
- (fixtureSourceContentId "source-a")
- Syntax.baseSyntaxInterfaceId
- [directSyntaxId, directSyntaxId])
- let
- firstParsed =
- parsedModuleId firstParsedKey "parsed"
- secondParsed =
- parsedModuleId secondParsedKey "parsed"
- firstArtifactKey <- expectRight
- (Semantic.moduleArtifactKey
- (fixtureOwner fixture)
- firstParsed
- []
- (fixtureTheory fixture))
- secondArtifactKey <- expectRight
- (Semantic.moduleArtifactKey
- (fixtureOwner fixture)
- secondParsed
- []
- (fixtureTheory fixture))
- let firstArtifact =
- Semantic.moduleArtifactId firstArtifactKey
- secondArtifact =
- Semantic.moduleArtifactId secondArtifactKey
- assertBool
- "module artifact binds parsed source identity"
- (firstArtifact /= secondArtifact)
- let semanticId =
- Semantic.semanticInterfaceAssertedId
- (fixtureInterface fixture)
- assertEqual
- "prefix identity rejects duplicate direct semantics"
- (Left
- (Semantic.DuplicateInitialPrefixSemanticInput
- semanticId))
- (Semantic.initialPrefixContextId
- (fixtureTheory fixture)
- (fixtureOwner fixture)
- [semanticId, semanticId])
- assertEqual
- "module artifact key cache round trip"
- (Right firstArtifactKey)
- (decodeCache
- Semantic.getModuleArtifactKeyCache
- (encodeCache
- (Semantic.putModuleArtifactKeyCache
- firstArtifactKey)))
- syntax <- makeSyntax "artifact"
- let artifactResult =
- Semantic.moduleArtifactResult
- firstArtifactKey
- (Syntax.moduleSyntaxAssertedId syntax)
- (Semantic.semanticInterfaceAssertedId
- (fixtureInterface fixture))
- assertEqual
- "module artifact root round trip"
- (Right artifactResult)
- (decodeCache
- (Semantic.getModuleArtifactResultCache
- firstArtifact)
- (encodeCache
- (Semantic.putModuleArtifactResultCache
- artifactResult)))
-
-
-data Fixture = Fixture
- { fixtureTheory :: !Identity.TheoryId
- , fixtureOwner :: !ModuleName
- , fixtureTheorem :: !Identity.TheoremRef
- , fixtureDelta :: !Semantic.DeclarationInterfaceDelta
- , fixtureInterface :: !Semantic.SemanticInterface
- , fixtureInitialPrefix :: !Semantic.PrefixContextId
- , fixtureNextPrefix :: !Semantic.PrefixContextId
- }
-
-makeFixture :: IO Fixture
-makeFixture = do
- foundation <- expectRight Foundation.checkedFoundation
- namespaceDigest <- expectRight
- (hashCanonicalFields
- "semantic-test-namespace"
- ["root"])
- relative <- expectRight (safeRelativePath "module.tex")
- closure <- expectRight
- (Identity.validateObjectClosure
- (Identity.theoryId foundation)
- [])
- proposition <- expectRight
- (Identity.validatePropositionContent
- closure
- Core.CFalsum)
- let theory =
- Identity.theoryId foundation
- owner =
- moduleNameFromParts
- (sourceNamespaceIdFromDigest namespaceDigest)
- relative
- reference =
- Identity.theoremRef
- theory
- (Identity.checkedPropositionId proposition)
- authority =
- Authority.factAuthority
- reference
- Authority.cleanAuthoritySafety
- occurrence =
- Semantic.semanticFactOccurrence
- (Semantic.factSlot owner (localFactOrdinal 0))
- authority
- Semantic.SearchEligible
- slot =
- Semantic.declarationSlot
- owner
- (localDeclarationOrdinal 0)
- delta <- expectRight
- (Semantic.declarationInterfaceDelta
- slot
- [occurrence]
- [ Semantic.semanticAlias
- (Semantic.semanticName "theorem")
- (Semantic.semanticFactOccurrenceFingerprint
- (Semantic.factSlot owner (localFactOrdinal 0))
- authority)
- ]
- []
- [Identity.checkedPropositionId proposition]
- Semantic.emptySemanticEnvironmentDelta)
- interface <- expectRight
- (Semantic.semanticInterface owner [] [delta])
- initial <- expectRight
- (Semantic.initialPrefixContextId theory owner [])
- pure
- Fixture
- { fixtureTheory = theory
- , fixtureOwner = owner
- , fixtureTheorem = reference
- , fixtureDelta = delta
- , fixtureInterface = interface
- , fixtureInitialPrefix = initial
- , fixtureNextPrefix =
- Semantic.nextPrefixContextId initial delta
- }
-
-makeSyntax :: Text -> IO Syntax.ModuleSyntaxInterface
-makeSyntax command = do
- delta <- expectRight
- (Syntax.canonicalSyntaxDelta
- [Syntax.CanonicalStructureOperation command])
- expectRight (Syntax.moduleSyntaxInterface [] delta)
-
-fixtureSourceContentId :: ByteString -> SourceContentId
-fixtureSourceContentId bytes =
- either
- (impossible . show)
- id
- (decodeCache
- getSourceContentIdCache
- (encodeCache
- (putCacheDigest
- (hashCacheFields
- "semantic-test-source"
- [bytes]))))
-
-expectRight :: Show error => Either error value -> IO value
-expectRight = \case
- Left err ->
- assertFailure (show err) >> fail "unreachable"
- Right value ->
- pure value
diff --git a/source/Test/Unit/Source.hs b/source/Test/Unit/Source.hs
deleted file mode 100644
index a8e4506..0000000
--- a/source/Test/Unit/Source.hs
+++ /dev/null
@@ -1,2581 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-{-# LANGUAGE OverloadedStrings #-}
-{-# LANGUAGE PatternSynonyms #-}
-
-module Test.Unit.Source (unitTests) where
-
-import Base
-import Checking.Foundation qualified as Foundation
-import Checking.Identity qualified as Identity
-import Checking.Semantic qualified as Semantic
-import Felix.Cache.Codec qualified as Cache
-import Felix.Module qualified as Module
-import Felix.Parse qualified as Parse
-import Felix.Parsed.Identity qualified as ParsedIdentity
-import Felix.Parsed.Payload qualified as Parsed
-import Felix.Prelude qualified as Prelude
-import Felix.Source
-import Felix.Source.Content qualified as Content
-import Felix.Source.Graph
-import Felix.Store qualified as Store
-import Report.Location
- ( FileId(..)
- , FileIdAllocator(..)
- , Location(..)
- , LocationRegistrationError(..)
- , allocateFileId
- , locColumn
- , locFile
- , locFileId
- , locLine
- , lookupFileIdentityPath
- )
-import Syntax.Abstract qualified as Raw
-import Syntax.Adapt qualified as Adapt
-import Syntax.Interface qualified as Interface
-import Syntax.Token (runLexer)
-
-import Control.Exception (bracket, evaluate)
-import Data.ByteString qualified as ByteString
-import Data.IORef
-import Data.List qualified as List
-import Data.List.NonEmpty qualified as NonEmpty
-import Data.Text qualified as Text
-import Data.Word (Word8, Word16)
-import Database.SQLite.Simple qualified as SQLite
-import System.Directory qualified as Directory
-import System.FilePath.Posix qualified as Posix
-import System.Posix.Files qualified as PosixFiles
-import Test.Tasty
-import Test.Tasty.HUnit
-
-
-unitTests :: TestTree
-unitTests = testGroup "Source resolution"
- [ testCase "validates mount-root-relative POSIX paths" validatesRelativePaths
- , testCase "rejects duplicate source mount ids" rejectsDuplicateMountIds
- , testCase "rejects duplicate canonical mount roots" rejectsDuplicateMountRoots
- , testCase "permits missing and rejects non-directory mounts"
- validatesMountRootTypes
- , testCase "rejects relative exact roots" rejectsRelativeExactRoots
- , testCase "retains exact root spelling as diagnostic trivia" retainsRootSpelling
- , testCase "searched and exact roots share canonical identity" rootFormsShareIdentity
- , testCase "attributes nested sources to the most specific mount" attributesNestedSources
- , testCase "configured order selects searched candidates" candidateOrderSelectsWinner
- , testCase "rejects a higher-priority special source"
- rejectsHigherPrioritySpecialSource
- , testCase "rejects exact roots outside configured mounts" rejectsOutsideExactRoot
- , testCase "loads source text as strict UTF-8" loadsStrictUtf8
- , testCase "reports malformed UTF-8 sequence starts"
- reportsInvalidUtf8Offsets
- , testCase "reserves the all-ones file identifier"
- preservesReservedFileId
- , testCase "builds an imported-before-importer source graph" buildsSourceGraph
- , testCase "rejects the packaged prelude as ordinary source"
- rejectsPackagedPreludeAsOrdinarySource
- , testCase "orders sibling imports by textual occurrence"
- ordersSiblingImports
- , testCase "orders shared dependencies before their importers"
- ordersSharedDependencies
- , testCase "retains repeated import-edge occurrences" retainsRepeatedImports
- , testCase "deduplicates canonical source nodes" deduplicatesCanonicalNodes
- , testCase "reports missing imports at their source location" reportsMissingImports
- , testCase "rejects unsafe imports at their source location" rejectsUnsafeImports
- , testCase "reports the located import cycle chain" reportsImportCycles
- , testCase "rejects malformed imported source before discovery" rejectsMalformedImportedSource
- , testCase "builds empty modules through the ordinary pipeline"
- buildsEmptyModules
- , testCase "identifies owner-independent parsed modules"
- identifiesOwnerIndependentParsedModules
- , testCase "keys effective direct syntax inputs"
- keysEffectiveDirectSyntaxInputs
- , testCase "reuses exact parsed syntax on a warm pass"
- reusesExactParsedSyntax
- , testCase "invalidates exact parsed inputs transitively"
- invalidatesExactParsedInputs
- , testCase "rebinds relocated parsed artifacts"
- rebindsRelocatedParsedArtifacts
- , testCase "rejects a corrupted cached declaration anchor"
- rejectsCorruptedCachedDeclarationAnchor
- , testCase "parses source-local blocks in graph order" parsesSourceGraph
- , testCase "does not leak syntax between sibling imports"
- rejectsSiblingSyntaxLeakage
- , testCase "parses source fixity levels and grouping"
- parsesSourceFixities
- , testCase "parses cdot and symdiff fixities"
- parsesLibraryFixities
- , testCase "validates source pragma associations"
- validatesSourcePragmaAssociations
- , testCase "rejects fixed-base category mismatches"
- rejectsFixedBaseCategoryMismatch
- , testCase "retains multi-item syntax occurrence order"
- retainsMultiItemSyntaxOccurrences
- , testCase "propagates and coalesces imported syntax"
- propagatesImportedSyntax
- , testCase "rejects unequal imported syntax"
- rejectsUnequalImportedSyntax
- , testCase "qualifies same-display cross-mount collisions"
- distinguishesPhysicalSourceLocations
- , testCase "retains each workspace location display path"
- retainsWorkspaceLocationDisplayPath
- , testCase "reports imported scanner errors before importer tokenizer errors"
- reportsImportedScannerErrorFirst
- , testCase "returns malformed lexical declarations as typed errors"
- reportsMalformedLexicalDeclaration
- , testCase "validates inductive function patterns during scanning"
- rejectsMalformedInductivePattern
- , testCase "scans and parses adjective signatures"
- acceptsAdjectiveSignature
- , testCase "rejects malformed math-led signature heads"
- rejectsMalformedSignatureHead
- , testCase "locates conflicting declarations within one environment"
- reportsSameSourceLexiconCollision
- , testCase "accepts the first source declaration of a built-in pattern"
- acceptsBuiltinSourceDeclaration
- , testCase "keeps the built-in marker for a prefix predicate declaration"
- acceptsBuiltinPrefixPredicateDeclaration
- , testCase "does not rescan repeated canonical imports"
- avoidsAliasImportLexiconCollision
- , testCase "parses loaded sources without rereading files" parsesWithoutRereading
- , testCase "returns source-local failures after prior chunk callbacks"
- returnsSourceParseFailures
- , testCase "rejects guarded symbolic declarations before publication"
- rejectsGuardedSymbolicDeclarations
- ]
-
-validatesRelativePaths :: Assertion
-validatesRelativePaths = do
- assertRight (safeRelativePath "theory/set.tex")
- assertRight (safeRelativePath "theory\\set.tex")
- assertLeft EmptyRelativePath (safeRelativePath "")
- assertLeft AbsoluteRelativePath (safeRelativePath "/theory.tex")
- assertLeft CurrentDirectoryComponent (safeRelativePath "./theory.tex")
- assertLeft ParentDirectoryComponent (safeRelativePath "a/../theory.tex")
- assertLeft EmptyPathComponent (safeRelativePath "a//theory.tex")
- assertLeft EmptyPathComponent (safeRelativePath "a/")
- assertLeft NullPathCharacter (safeRelativePath "a\0b")
-
-rejectsDuplicateMountIds :: Assertion
-rejectsDuplicateMountIds =
- withTemporaryDirectory "felix-source-duplicate-id" \temp -> do
- result <- prepareSourceMounts
- [ (sourceMountId "same", temp Posix.</> "one")
- , (sourceMountId "same", temp Posix.</> "two")
- ]
- assertEqual
- "duplicate id"
- (Left (DuplicateSourceMountId (sourceMountId "same")))
- result
-
-rejectsDuplicateMountRoots :: Assertion
-rejectsDuplicateMountRoots =
- withTemporaryDirectory "felix-source-duplicate-root" \temp -> do
- result <- prepareSourceMounts
- [ (sourceMountId "one", temp)
- , (sourceMountId "two", temp Posix.</> ".")
- ]
- canonical <- Directory.canonicalizePath temp
- case result of
- Left (DuplicateCanonicalMountRoot root firstId secondId) -> do
- assertEqual "canonical root" canonical (canonicalPathFilePath root)
- assertEqual "first mount id" (sourceMountId "one") firstId
- assertEqual "second mount id" (sourceMountId "two") secondId
- Left err ->
- assertFailure ("expected DuplicateCanonicalMountRoot, got " <> show err)
- Right mounts ->
- assertFailure ("expected duplicate-root rejection, got " <> show mounts)
-
-validatesMountRootTypes :: Assertion
-validatesMountRootTypes =
- withTemporaryDirectory "felix-source-mount-type" \temp -> do
- let ident = sourceMountId "project"
- missing = temp Posix.</> "missing"
- regularFile = temp Posix.</> "file"
- assertRight =<< prepareSourceMounts [(ident, missing)]
-
- writeFile regularFile ""
- result <- prepareSourceMounts [(ident, regularFile)]
- case result of
- Left SourceMountNotDirectory{} ->
- pure ()
- Left err ->
- assertFailure
- ("expected SourceMountNotDirectory, got " <> show err)
- Right mounts ->
- assertFailure
- ("expected non-directory rejection, got " <> show mounts)
-
-rejectsRelativeExactRoots :: Assertion
-rejectsRelativeExactRoots =
- assertEqual
- "relative exact roots are rejected"
- (Left (ExistingRootNotAbsolute "entry.tex"))
- =<< existingRoot "entry.tex"
-
-retainsRootSpelling :: Assertion
-retainsRootSpelling =
- withTemporaryDirectory "felix-source-root-spelling" \temp -> do
- let source = temp Posix.</> "entry.tex"
- alias = temp Posix.</> "entry-alias.tex"
- writeFile source ""
- Directory.createFileLink source alias
- direct <- expectRight =<< existingRoot source
- throughAlias <- expectRight =<< existingRoot alias
- assertEqual "canonical request identity" direct throughAlias
- assertEqual "diagnostic spelling" alias
- (rootRequestSpelling throughAlias)
-
-rootFormsShareIdentity :: Assertion
-rootFormsShareIdentity =
- withTemporaryDirectory "felix-source-root-identity" \temp -> do
- let source = temp Posix.</> "entry.tex"
- writeFile source "source"
- mounts <- oneMount "project" temp
- searched <- expectRight (searchedRoot "entry.tex")
- exact <- expectRight =<< existingRoot source
- searchedLoaded <- expectRight =<< resolveAndLoadRoot mounts searched
- exactLoaded <- expectRight =<< resolveAndLoadRoot mounts exact
- assertEqual "loaded source" searchedLoaded exactLoaded
- assertEqual "source mount"
- (resolvedSourceMount (loadedSource searchedLoaded))
- (resolvedSourceMount (loadedSource exactLoaded))
- assertEqual "mount-relative source path"
- (resolvedSourceRelativePath (loadedSource searchedLoaded))
- (resolvedSourceRelativePath (loadedSource exactLoaded))
-
-rejectsPackagedPreludeAsOrdinarySource :: Assertion
-rejectsPackagedPreludeAsOrdinarySource = do
- packaged <- expectRight =<< Prelude.loadReservedPreludeSourceInput
- canonical <- expectJust "packaged canonical path"
- (Prelude.reservedPreludeSourceCanonicalPath packaged)
- let path = canonicalPathFilePath canonical
- mounts <- oneMount "packaged" (Posix.takeDirectory path)
- request <- expectRight (searchedRoot (Posix.takeFileName path))
- let validate = Prelude.rejectOrdinaryPreludeSourceGraph packaged
- syntaxInputs = const []
- Parse.parseSourceWorkspaceWithSyntaxInputsAndGraphValidation
- mounts request syntaxInputs validate >>= \case
- Left
- (Parse.SourceWorkspaceError
- (PackagedPreludeSelectedAsOrdinarySource source)) ->
- assertEqual "authority-free rejected path"
- canonical
- (resolvedSourceCanonicalPath source)
- other ->
- assertFailure
- ("unexpected authority-free result: " <> show other)
-
- withTemporaryDirectory "felix-reserved-parse-store" \temp -> do
- foundation <- expectRight Foundation.checkedFoundation
- store <- openTestStore
- (temp Posix.</> "store.sqlite")
- (Identity.theoryId foundation)
- Parse.parseSourceWorkspaceWithStoreAndSyntaxInputsAndGraphValidation
- store mounts request syntaxInputs validate >>= \case
- Left
- (Parse.ParseExecutionWorkspaceError
- (Parse.SourceWorkspaceError
- (PackagedPreludeSelectedAsOrdinarySource source))) ->
- assertEqual "typed rejected path"
- canonical
- (resolvedSourceCanonicalPath source)
- other ->
- assertFailure
- ("unexpected typed result: " <> show other)
- Store.closeStore store
-
-attributesNestedSources :: Assertion
-attributesNestedSources =
- withTemporaryDirectory "felix-source-nested-mount" \temp -> do
- let nested = temp Posix.</> "library"
- source = nested Posix.</> "entry.tex"
- Directory.createDirectory nested
- writeFile source "source"
- exact <- expectRight =<< existingRoot source
- outerFirst <- expectRight =<< prepareSourceMounts
- [ (sourceMountId "project", temp)
- , (sourceMountId "library", nested)
- ]
- innerFirst <- expectRight =<< prepareSourceMounts
- [ (sourceMountId "library", nested)
- , (sourceMountId "project", temp)
- ]
- searched <- expectRight (searchedRoot "library/entry.tex")
- outerFirstSource <- loadedSource <$> (expectRight =<< resolveAndLoadRoot outerFirst exact)
- innerFirstSource <- loadedSource <$> (expectRight =<< resolveAndLoadRoot innerFirst exact)
- searchedSource <- loadedSource <$> (expectRight =<< resolveAndLoadRoot outerFirst searched)
- assertEqual "order-independent attribution" outerFirstSource innerFirstSource
- assertEqual "root-form-independent attribution" outerFirstSource searchedSource
- assertEqual "most specific mount" (sourceMountId "library") (resolvedSourceMount outerFirstSource)
- assertEqual "mount-relative identity" "entry.tex"
- (safeRelativePathFilePath (resolvedSourceRelativePath outerFirstSource))
-
-candidateOrderSelectsWinner :: Assertion
-candidateOrderSelectsWinner =
- withTemporaryDirectory "felix-source-precedence" \temp -> do
- let firstRoot = temp Posix.</> "first"
- secondRoot = temp Posix.</> "second"
- firstSource = firstRoot Posix.</> "entry.tex"
- secondSource = secondRoot Posix.</> "entry.tex"
- Directory.createDirectory firstRoot
- Directory.createDirectory secondRoot
- writeFile firstSource "first"
- writeFile secondSource "second"
- request <- expectRight (searchedRoot "entry.tex")
- firstMounts <- expectRight =<< prepareSourceMounts
- [ (sourceMountId "first", firstRoot)
- , (sourceMountId "second", secondRoot)
- ]
- secondMounts <- expectRight =<< prepareSourceMounts
- [ (sourceMountId "second", secondRoot)
- , (sourceMountId "first", firstRoot)
- ]
- firstWinner <- expectRight =<< resolveAndLoadRoot firstMounts request
- secondWinner <- expectRight =<< resolveAndLoadRoot secondMounts request
- assertEqual "first configured source" "first" (loadedText firstWinner)
- assertEqual "reversed configured source" "second" (loadedText secondWinner)
-
-rejectsHigherPrioritySpecialSource :: Assertion
-rejectsHigherPrioritySpecialSource =
- withTemporaryDirectory "felix-source-special-precedence" \temp -> do
- let higherRoot = temp Posix.</> "higher"
- lowerRoot = temp Posix.</> "lower"
- higherSource = higherRoot Posix.</> "entry.tex"
- lowerSource = lowerRoot Posix.</> "entry.tex"
- Directory.createDirectory higherRoot
- Directory.createDirectory lowerRoot
- PosixFiles.createNamedPipe higherSource PosixFiles.ownerModes
- writeFile lowerSource "ordinary source"
- mounts <- expectRight =<< prepareSourceMounts
- [ (sourceMountId "higher", higherRoot)
- , (sourceMountId "lower", lowerRoot)
- ]
- request <- expectRight (searchedRoot "entry.tex")
- result <- resolveRoot mounts request
- case result of
- Left
- (SelectedSourceNotRegular
- (SearchedRootLookup relative)
- selectedPath
- canonical) -> do
- assertEqual "searched path"
- "entry.tex"
- (safeRelativePathFilePath relative)
- assertEqual "selected higher candidate"
- higherSource
- selectedPath
- canonicalHigher <-
- Directory.canonicalizePath higherSource
- assertEqual "selected canonical target"
- canonicalHigher
- (canonicalPathFilePath canonical)
- Left err ->
- assertFailure
- ("expected SelectedSourceNotRegular, got " <> show err)
- Right source ->
- assertFailure
- ("expected special-source rejection, got " <> show source)
-
-rejectsOutsideExactRoot :: Assertion
-rejectsOutsideExactRoot =
- withTemporaryDirectory "felix-source-outside-root" \temp -> do
- let mountRoot = temp Posix.</> "mount"
- outsideRoot = temp Posix.</> "outside"
- source = outsideRoot Posix.</> "entry.tex"
- Directory.createDirectory mountRoot
- Directory.createDirectory outsideRoot
- writeFile source "source"
- mounts <- oneMount "project" mountRoot
- exact <- expectRight =<< existingRoot source
- result <- resolveAndLoadRoot mounts exact
- case result of
- Left (RootOutsideConfiguredMount spelling _canonical) ->
- assertEqual "exact-root diagnostic spelling" source spelling
- Left err ->
- assertFailure ("expected RootOutsideConfiguredMount, got " <> show err)
- Right loaded ->
- assertFailure ("expected outside-root rejection, got " <> show loaded)
-
-loadsStrictUtf8 :: Assertion
-loadsStrictUtf8 =
- withTemporaryDirectory "felix-source-utf8" \temp -> do
- let source = temp Posix.</> "unicode.tex"
- bytes =
- ByteString.pack
- [ 0xCE, 0xB1, 0x20, 0xE2
- , 0x88, 0x88, 0x20, 0x41
- ]
- ByteString.writeFile source bytes
- mounts <- oneMount "project" temp
- request <- expectRight (searchedRoot "unicode.tex")
- loaded <- expectRight =<< resolveAndLoadRoot mounts request
- assertEqual "exact bytes" bytes (loadedBytes loaded)
- assertEqual "decoded text" ("α ∈ A" :: Text) (loadedText loaded)
- assertEqual
- "byte count"
- (fromIntegral (ByteString.length bytes))
- (loadedByteCount loaded)
- let identifier =
- Content.sourceContentId loaded
- assertEqual
- "content identity cache round trip"
- (Right identifier)
- (Cache.decodeCache
- Content.getSourceContentIdCache
- (Cache.encodeCache
- (Content.putSourceContentIdCache
- identifier)))
- ByteString.writeFile source (bytes <> "\n")
- changed <- expectRight
- =<< loadResolvedSource (loadedSource loaded)
- assertBool
- "exact byte edits change source identity"
- (identifier /= Content.sourceContentId changed)
-
-reportsInvalidUtf8Offsets :: Assertion
-reportsInvalidUtf8Offsets =
- withTemporaryDirectory "felix-source-invalid-utf8" \temp -> do
- let source = temp Posix.</> "invalid.tex"
- mounts <- oneMount "project" temp
- request <- expectRight (searchedRoot "invalid.tex")
- let assertOffset label bytes expected = do
- ByteString.writeFile source (ByteString.pack bytes)
- result <- resolveAndLoadRoot mounts request
- case result of
- Left (SourceDecodeError _source offset) ->
- assertEqual label expected offset
- Left err ->
- assertFailure
- ("expected SourceDecodeError, got " <> show err)
- Right loaded ->
- assertFailure
- ("expected malformed UTF-8 rejection, got "
- <> show loaded)
- assertOffset "malformed sequence start" [0x61, 0xC3, 0x28] 1
- assertOffset "incomplete sequence start" [0x61, 0xC3] 1
-
-preservesReservedFileId :: Assertion
-preservesReservedFileId =
- case allocateFileId boundaryAllocator of
- Left err ->
- assertFailure
- ("could not allocate last available file id: " <> show err)
- Right (fileId, exhaustedAllocator) -> do
- assertEqual "last available file id"
- (maxBound - 1)
- (unFileId fileId)
- assertBool "allocator returned reserved file id"
- (unFileId fileId /= maxBound)
- assertEqual "allocator reports exhaustion"
- (Left FileIdSpaceExhausted)
- (allocateFileId exhaustedAllocator)
- where
- boundaryAllocator =
- FileIdAllocator
- (fromIntegral (maxBound :: Word16) - 1)
-
-buildsSourceGraph :: Assertion
-buildsSourceGraph =
- withTemporaryDirectory "felix-source-graph" \temp -> do
- writeTheory (temp Posix.</> "shared.tex") [] "shared"
- writeTheory (temp Posix.</> "entry.tex") ["shared.tex"] "entry"
- mounts <- oneMount "project" temp
- request <- expectRight (searchedRoot "entry.tex")
- graph <- expectRight =<< buildResolvedSourceGraph mounts request
- assertEqual "two source nodes" 2 (length (sourceGraphNodes graph))
- case sourceGraphImportEdges graph of
- [edge] -> do
- assertEqual "root imports" (sourceGraphRoot graph) (sourceImportingNode edge)
- assertEqual
- "imported-before-importer order"
- [sourceImportedNode edge, sourceGraphRoot graph]
- ( sourceNodeCanonicalPathForTest
- <$> toList
- (sourceGraphImportedBeforeImporter graph)
- )
- assertEqual "import location line" 1
- (locLine (importLocation (sourceImportReference edge)))
- assertEqual "selected location path" "entry.tex"
- (locFile (importLocation (sourceImportReference edge)))
- edges ->
- assertFailure ("expected one import edge, got " <> show edges)
-
-ordersSiblingImports :: Assertion
-ordersSiblingImports =
- withTemporaryDirectory "felix-source-sibling-order" \temp -> do
- writeTheory (temp Posix.</> "a.tex") [] "a"
- writeTheory (temp Posix.</> "b.tex") [] "b"
- writeTheory
- (temp Posix.</> "entry.tex")
- ["a.tex", "b.tex"]
- "entry"
- graph <- buildSearchedGraph temp "entry.tex"
- order <- sourceGraphOrderPaths graph
- assertEqual "DFS completion order"
- ["a.tex", "b.tex", "entry.tex"]
- order
-
-ordersSharedDependencies :: Assertion
-ordersSharedDependencies =
- withTemporaryDirectory "felix-source-shared-order" \temp -> do
- writeTheory (temp Posix.</> "shared.tex") [] "shared"
- writeTheory (temp Posix.</> "a.tex") ["shared.tex"] "a"
- writeTheory (temp Posix.</> "b.tex") ["shared.tex"] "b"
- writeTheory
- (temp Posix.</> "entry.tex")
- ["a.tex", "b.tex"]
- "entry"
- graph <- buildSearchedGraph temp "entry.tex"
- order <- sourceGraphOrderPaths graph
- assertEqual "shared dependency occurs once before both importers"
- ["shared.tex", "a.tex", "b.tex", "entry.tex"]
- order
-
-retainsRepeatedImports :: Assertion
-retainsRepeatedImports =
- withTemporaryDirectory "felix-source-repeated-import" \temp -> do
- writeTheory (temp Posix.</> "shared.tex") [] "shared"
- writeTheory
- (temp Posix.</> "entry.tex")
- ["shared.tex", "shared.tex"]
- "entry"
- graph <- buildSearchedGraph temp "entry.tex"
- assertEqual "canonical node count" 2 (length (sourceGraphNodes graph))
- assertEqual "repeated edge count" 2 (length (sourceGraphImportEdges graph))
-
-deduplicatesCanonicalNodes :: Assertion
-deduplicatesCanonicalNodes =
- withTemporaryDirectory "felix-source-canonical-dedup" \temp -> do
- let shared = temp Posix.</> "shared.tex"
- alias = temp Posix.</> "alias.tex"
- writeTheory shared [] "shared"
- Directory.createFileLink shared alias
- writeTheory
- (temp Posix.</> "entry.tex")
- ["shared.tex", "alias.tex"]
- "entry"
- graph <- buildSearchedGraph temp "entry.tex"
- assertEqual "one node for symlink aliases" 2 (length (sourceGraphNodes graph))
- case sourceGraphImportEdges graph of
- [firstEdge, secondEdge] ->
- assertEqual
- "both occurrences reach one node"
- (sourceImportedNode firstEdge)
- (sourceImportedNode secondEdge)
- edges ->
- assertFailure ("expected two import edges, got " <> show edges)
-
-reportsMissingImports :: Assertion
-reportsMissingImports =
- withTemporaryDirectory "felix-source-missing-import" \temp -> do
- writeFile
- (temp Posix.</> "entry.tex")
- (unlines
- [ "% heading"
- , "\\import{missing.tex}"
- , theoryBlock "entry"
- ])
- mounts <- oneMount "project" temp
- request <- expectRight (searchedRoot "entry.tex")
- result <- buildResolvedSourceGraph mounts request
- case result of
- Left (SourceNotFound (ImportedSourceLookup _ reference) _candidates) -> do
- assertEqual "missing import line" 2 (locLine (importLocation reference))
- assertEqual "missing import source" "entry.tex"
- (locFile (importLocation reference))
- Left err ->
- assertFailure ("expected located SourceNotFound, got " <> show err)
- Right graph ->
- assertFailure ("expected missing-import rejection, got " <> show graph)
-
-rejectsUnsafeImports :: Assertion
-rejectsUnsafeImports =
- withTemporaryDirectory "felix-source-unsafe-import" \temp -> do
- writeTheory (temp Posix.</> "entry.tex") ["./shared.tex"] "entry"
- mounts <- oneMount "project" temp
- request <- expectRight (searchedRoot "entry.tex")
- result <- buildResolvedSourceGraph mounts request
- case result of
- Left (InvalidImportPath _source location raw CurrentDirectoryComponent) -> do
- assertEqual "raw import" "./shared.tex" raw
- assertEqual "unsafe import line" 1 (locLine location)
- assertEqual "unsafe import source" "entry.tex" (locFile location)
- Left err ->
- assertFailure ("expected InvalidImportPath, got " <> show err)
- Right graph ->
- assertFailure ("expected unsafe-import rejection, got " <> show graph)
-
-reportsImportCycles :: Assertion
-reportsImportCycles =
- withTemporaryDirectory "felix-source-cycle" \temp -> do
- writeTheory (temp Posix.</> "a.tex") ["b.tex"] "a"
- writeTheory (temp Posix.</> "b.tex") ["a.tex"] "b"
- mounts <- oneMount "project" temp
- request <- expectRight (searchedRoot "a.tex")
- result <- buildResolvedSourceGraph mounts request
- case result of
- Left (SourceImportCycle steps) -> do
- assertEqual "cycle length" 2 (length steps)
- assertEqual
- "cycle importer sequence"
- ["a.tex", "b.tex"]
- [ safeRelativePathFilePath
- (resolvedSourceRelativePath (cycleImporter step))
- | step <- toList steps
- ]
- assertEqual
- "cycle import locations"
- ["a.tex", "b.tex"]
- [ locFile (importLocation (cycleImport step))
- | step <- toList steps
- ]
- Left err ->
- assertFailure ("expected SourceImportCycle, got " <> show err)
- Right graph ->
- assertFailure ("expected cycle rejection, got " <> show graph)
-
-rejectsMalformedImportedSource :: Assertion
-rejectsMalformedImportedSource =
- withTemporaryDirectory "felix-source-import-utf8" \temp -> do
- writeTheory (temp Posix.</> "entry.tex") ["bad.tex"] "entry"
- ByteString.writeFile
- (temp Posix.</> "bad.tex")
- (ByteString.pack [0x61, 0xFF])
- mounts <- oneMount "project" temp
- request <- expectRight (searchedRoot "entry.tex")
- result <- buildResolvedSourceGraph mounts request
- case result of
- Left (SourceDecodeError source offset) -> do
- assertEqual "bad source" "bad.tex"
- (safeRelativePathFilePath (resolvedSourceRelativePath source))
- assertEqual "bad byte offset" 1 offset
- Left err ->
- assertFailure ("expected SourceDecodeError, got " <> show err)
- Right graph ->
- assertFailure ("expected malformed-source rejection, got " <> show graph)
-
-buildsEmptyModules :: Assertion
-buildsEmptyModules =
- withTemporaryDirectory "felix-source-empty" \temp ->
- forM_
- [ ("empty.tex", "")
- , ("comments.tex", "% heading\n% body")
- ]
- \(relative, contents) -> do
- writeFile (temp Posix.</> relative) contents
- graph <- buildSearchedGraph temp relative
- assertEqual
- "one ordinary graph node"
- 1
- (length (sourceGraphNodes graph))
- emittedRef <- newIORef (0 :: Int)
- workspace <-
- expectRight
- =<< Parse.parseResolvedSourceGraphWith
- graph
- (\_source _block ->
- modifyIORef' emittedRef (+ 1))
- assertEqual
- "no block callbacks"
- 0
- =<< readIORef emittedRef
- assertEqual
- "empty parsed projection"
- []
- (Parse.importedBeforeImporterBlocks workspace)
- assertBool
- "empty syntax declarations"
- (null
- (Interface.canonicalSyntaxDeltaEntries
- (Interface.moduleSyntaxLocalDelta
- (Parse.parsedModuleSyntaxInterface
- (Parse.parsedWorkspaceRootModule
- workspace)))))
-
-identifiesOwnerIndependentParsedModules :: Assertion
-identifiesOwnerIndependentParsedModules =
- withTemporaryDirectory "felix-parsed-identity" \temp -> do
- let firstRoot = temp Posix.</> "first"
- secondRoot = temp Posix.</> "second"
- bytes = axiomBlock "same" "x = x"
- Directory.createDirectory firstRoot
- Directory.createDirectory secondRoot
- writeFile (firstRoot Posix.</> "entry.tex") bytes
- writeFile (secondRoot Posix.</> "entry.tex") bytes
- firstWorkspace <- expectRight
- =<< Parse.parseResolvedSourceGraph
- =<< buildSearchedGraph firstRoot "entry.tex"
- secondWorkspace <- expectRight
- =<< Parse.parseResolvedSourceGraph
- =<< buildSearchedGraph secondRoot "entry.tex"
- let first = Parse.parsedWorkspaceRootModule firstWorkspace
- second = Parse.parsedWorkspaceRootModule secondWorkspace
- assertBool
- "logical owners remain distinct"
- ( Module.moduleName (Parse.parsedModuleAddress first)
- /= Module.moduleName (Parse.parsedModuleAddress second)
- )
- assertEqual
- "equal bytes retain one content identity"
- (Parse.parsedModuleSourceContentId first)
- (Parse.parsedModuleSourceContentId second)
- assertEqual
- "physical source registration is outside parsed identity"
- (Parse.parsedModuleId first)
- (Parse.parsedModuleId second)
- assertEqual
- "canonical payload is owner-independent"
- (Parse.parsedModulePayload first)
- (Parse.parsedModulePayload second)
- let payload = Parse.parsedModulePayload first
- assertEqual
- "canonical parsed payload cache round trip"
- (Right payload)
- (Cache.decodeCache
- Parsed.getCanonicalParsedPayloadCache
- (Cache.encodeCache
- (Parsed.putCanonicalParsedPayloadCache payload)))
- rebound <- expectRight
- (Parsed.decodeCanonicalParsedPayload
- (FileId 123)
- payload)
- case Parsed.decodedParsedBlocks rebound of
- Raw.BlockAxiom location _title _marker _axiom : _ ->
- assertEqual
- "decoded locations bind only to the current live file"
- (Just (FileId 123))
- (locFileId location)
- blocks ->
- assertFailure
- ("expected decoded axiom, got " <> show blocks)
- writeFile
- (secondRoot Posix.</> "entry.tex")
- (bytes <> "% content identity change\n")
- changedWorkspace <- expectRight
- =<< Parse.parseResolvedSourceGraph
- =<< buildSearchedGraph secondRoot "entry.tex"
- assertBool
- "exact source changes parsed identity"
- ( Parse.parsedModuleId first
- /= Parse.parsedModuleId
- (Parse.parsedWorkspaceRootModule changedWorkspace)
- )
-
-keysEffectiveDirectSyntaxInputs :: Assertion
-keysEffectiveDirectSyntaxInputs =
- withTemporaryDirectory "felix-parsed-syntax-input" \temp -> do
- let firstRoot = temp Posix.</> "first"
- secondRoot = temp Posix.</> "second"
- rootBytes = "\\import{notation.tex}\n"
- Directory.createDirectory firstRoot
- Directory.createDirectory secondRoot
- writeFile (firstRoot Posix.</> "entry.tex") rootBytes
- writeFile (secondRoot Posix.</> "entry.tex") rootBytes
- writeFile
- (firstRoot Posix.</> "notation.tex")
- (syntaxFunctionDefinition
- "first_notation"
- "firstop"
- (Just "%! infixl 1"))
- writeFile
- (secondRoot Posix.</> "notation.tex")
- (syntaxFunctionDefinition
- "second_notation"
- "secondop"
- (Just "%! infixl 1"))
- firstWorkspace <- expectRight
- =<< Parse.parseResolvedSourceGraph
- =<< buildSearchedGraph firstRoot "entry.tex"
- secondWorkspace <- expectRight
- =<< Parse.parseResolvedSourceGraph
- =<< buildSearchedGraph secondRoot "entry.tex"
- let first = Parse.parsedWorkspaceRootModule firstWorkspace
- second = Parse.parsedWorkspaceRootModule secondWorkspace
- assertEqual
- "root source bytes are unchanged"
- (Parse.parsedModuleSourceContentId first)
- (Parse.parsedModuleSourceContentId second)
- assertBool
- "effective syntax changes the parsed key"
- (Parse.parsedModuleKey first /= Parse.parsedModuleKey second)
- assertBool
- "effective syntax changes parsed identity"
- (Parse.parsedModuleId first /= Parse.parsedModuleId second)
-
-reusesExactParsedSyntax :: Assertion
-reusesExactParsedSyntax =
- withTemporaryDirectory "felix-parsed-warm" \temp -> do
- let datatype = unlines
- [ "\\begin{datatype}\\label{multi_item}"
- , " Define $\\itemkind$ inductively as follows."
- , " \\begin{enumerate}"
- , " \\item $\\itemzero \\in \\itemkind$."
- , " \\item $\\itemsucc{x} \\in \\itemkind$ for $x \\in \\itemkind$."
- , " \\end{enumerate}"
- , "\\end{datatype}"
- ]
- writeFile
- (temp Posix.</> "entry.tex")
- (builtinZeroDefinition "source_zero" <> datatype)
- mounts <- oneMount "project" temp
- request <- expectRight (searchedRoot "entry.tex")
- foundation <- expectRight Foundation.checkedFoundation
- store <- openTestStore
- (temp Posix.</> "store.sqlite")
- (Identity.theoryId foundation)
- coldCallbacks <- newIORef (0 :: Int)
- cold <- expectParseExecution
- =<< Parse.parseSourceWorkspaceWithStoreAndSyntaxInputsAndCallback
- store mounts request (const [])
- (\_source _block -> modifyIORef' coldCallbacks (+ 1))
- warmCallbacks <- newIORef (0 :: Int)
- warm <- expectParseExecution
- =<< Parse.parseSourceWorkspaceWithStoreAndSyntaxInputsAndCallback
- store mounts request (const [])
- (\_source _block -> modifyIORef' warmCallbacks (+ 1))
- let coldRoot = Parse.parsedWorkspaceRootModule cold
- warmRoot = Parse.parsedWorkspaceRootModule warm
- let expectedChunkCount =
- length (Parse.parsedModuleBlocks warmRoot)
- assertBool "fixture has source chunks" (expectedChunkCount > 0)
- assertEqual "cold callbacks" expectedChunkCount
- =<< readIORef coldCallbacks
- assertEqual "warm callbacks" expectedChunkCount
- =<< readIORef warmCallbacks
- assertEqual "warm blocks" (Parse.parsedModuleBlocks coldRoot)
- (Parse.parsedModuleBlocks warmRoot)
- assertEqual "warm occurrences"
- (Parse.parsedModuleSyntaxOccurrences coldRoot)
- (Parse.parsedModuleSyntaxOccurrences warmRoot)
- assertEqual "warm syntax interface"
- (Parse.parsedModuleSyntaxInterface coldRoot)
- (Parse.parsedModuleSyntaxInterface warmRoot)
- assertEqual "warm parsed identity"
- (Parse.parsedModuleId coldRoot)
- (Parse.parsedModuleId warmRoot)
- case Parse.parsedModuleSyntaxOccurrences warmRoot of
- first : second : third : fourth : [] -> do
- assertEqual "fixed source marker" "source_zero"
- (Parse.parsedSyntaxOccurrenceMarker first)
- case Parse.parsedSyntaxOccurrenceEntry first of
- Interface.CanonicalExpressionFunction
- _pattern marker _fixity ->
- assertEqual "fixed authoritative marker" "zero" marker
- entry ->
- assertFailure
- ("unexpected fixed cached entry: " <> show entry)
- assertEqual "multi-item block order" [1, 1, 1]
- (Parse.parsedSyntaxOccurrenceBlockIndex
- <$> [second, third, fourth])
- assertEqual "multi-item scanner order"
- ["multi_item", "itemzero", "itemsucc"]
- (Parse.parsedSyntaxOccurrenceMarker
- <$> [second, third, fourth])
- case drop 1 (Parse.parsedModuleBlocks warmRoot) of
- block : _ ->
- case block of
- Raw.BlockData _location _title marker _datatype ->
- assertEqual "cached declaration-head anchor"
- marker
- (Parse.parsedSyntaxOccurrenceMarker second)
- other ->
- assertFailure
- ("expected cached datatype block, got "
- <> show other)
- [] ->
- assertFailure "cached datatype block is absent"
- occurrences ->
- assertFailure
- ("unexpected cached syntax occurrences: "
- <> show occurrences)
- assertEqual "cold callback projection" 2
- =<< readIORef coldCallbacks
- assertEqual "warm callback projection" 2
- =<< readIORef warmCallbacks
- Store.closeStore store
-
-invalidatesExactParsedInputs :: Assertion
-invalidatesExactParsedInputs =
- withTemporaryDirectory "felix-parsed-invalidation" \temp -> do
- let notationPath = temp Posix.</> "notation.tex"
- entryPath = temp Posix.</> "entry.tex"
- notation associativity level =
- syntaxFunctionDefinition
- "join"
- "join"
- (Just
- ("%! " <> associativity <> " " <> show level))
- entry suffix =
- "\\import{notation.tex}\n"
- <> axiomBlock
- "imported_syntax_use"
- "a\\join b\\join c = a"
- <> suffix
- writeFile notationPath (notation "infixl" (1 :: Int))
- writeFile entryPath (entry "")
- mounts <- oneMount "project" temp
- request <- expectRight (searchedRoot "entry.tex")
- foundation <- expectRight Foundation.checkedFoundation
- store <- openTestStore
- (temp Posix.</> "store.sqlite")
- (Identity.theoryId foundation)
- let parse =
- expectParseExecution
- =<< Parse.parseSourceWorkspaceWithStoreAndSyntaxInputs
- store mounts request (const [])
- coldWorkspace <- parse
- warmWorkspace <- parse
- coldNotation <- findParsedModule "notation.tex" coldWorkspace
- warmNotation <- findParsedModule "notation.tex" warmWorkspace
- let coldRoot = Parse.parsedWorkspaceRootModule coldWorkspace
- warmRoot = Parse.parsedWorkspaceRootModule warmWorkspace
- assertEqual "unchanged import identity"
- (Parse.parsedModuleId coldNotation)
- (Parse.parsedModuleId warmNotation)
- assertEqual "unchanged importer identity"
- (Parse.parsedModuleId coldRoot)
- (Parse.parsedModuleId warmRoot)
-
- writeFile entryPath (entry "% formatting-only edit\n")
- editedWorkspace <- parse
- editedNotation <- findParsedModule "notation.tex" editedWorkspace
- let editedRoot = Parse.parsedWorkspaceRootModule editedWorkspace
- assertEqual "cached import retains identity"
- (Parse.parsedModuleId warmNotation)
- (Parse.parsedModuleId editedNotation)
- assertBool "exact source edit changes importer key"
- (Parse.parsedModuleKey warmRoot
- /= Parse.parsedModuleKey editedRoot)
- assertEqual "formatting retains parsed projection"
- (Parse.parsedModulePayload warmRoot)
- (Parse.parsedModulePayload editedRoot)
-
- writeFile notationPath (notation "infixr" (2 :: Int))
- syntaxWorkspace <- parse
- syntaxNotation <- findParsedModule "notation.tex" syntaxWorkspace
- let syntaxRoot = Parse.parsedWorkspaceRootModule syntaxWorkspace
- assertBool "local syntax identity changes"
- ( Interface.moduleSyntaxAssertedId
- (Parse.parsedModuleSyntaxInterface editedNotation)
- /= Interface.moduleSyntaxAssertedId
- (Parse.parsedModuleSyntaxInterface syntaxNotation)
- )
- assertEqual "importer source is unchanged"
- (Parse.parsedModuleSourceContentId editedRoot)
- (Parse.parsedModuleSourceContentId syntaxRoot)
- assertBool "direct syntax invalidates importer key"
- (Parse.parsedModuleKey editedRoot
- /= Parse.parsedModuleKey syntaxRoot)
- Store.closeStore store
-
-rebindsRelocatedParsedArtifacts :: Assertion
-rebindsRelocatedParsedArtifacts =
- withTemporaryDirectory "felix-parsed-relocation" \temp -> do
- let firstRoot = temp Posix.</> "first"
- secondRoot = temp Posix.</> "second"
- sourceBytes = axiomBlock "same" "x = x"
- Directory.createDirectory firstRoot
- Directory.createDirectory secondRoot
- writeFile (firstRoot Posix.</> "entry.tex") sourceBytes
- writeFile (secondRoot Posix.</> "entry.tex") sourceBytes
- firstMounts <- oneMount "first" firstRoot
- secondMounts <- oneMount "second" secondRoot
- request <- expectRight (searchedRoot "entry.tex")
- foundation <- expectRight Foundation.checkedFoundation
- let theory = Identity.theoryId foundation
- store <- openTestStore (temp Posix.</> "store.sqlite") theory
- firstWorkspace <- expectParseExecution
- =<< Parse.parseSourceWorkspaceWithStoreAndSyntaxInputs
- store firstMounts request (const [])
- secondWorkspace <- expectParseExecution
- =<< Parse.parseSourceWorkspaceWithStoreAndSyntaxInputs
- store secondMounts request (const [])
- let first = Parse.parsedWorkspaceRootModule firstWorkspace
- second = Parse.parsedWorkspaceRootModule secondWorkspace
- firstSource = Parse.parsedModuleResolved first
- secondSource = Parse.parsedModuleResolved second
- assertEqual "relocation retains parsed identity"
- (Parse.parsedModuleId first)
- (Parse.parsedModuleId second)
- assertEqual "relocation retains canonical payload"
- (Parse.parsedModulePayload first)
- (Parse.parsedModulePayload second)
- assertBool "relocation rebinds the physical source"
- (resolvedSourceCanonicalPath firstSource
- /= resolvedSourceCanonicalPath secondSource)
- assertBool "relocation rebinds the logical owner"
- (Parse.parsedModuleAddress first
- /= Parse.parsedModuleAddress second)
- firstFileId <- expectJust "first location file id"
- (locFileId (onlyAxiomLocation first))
- secondFileId <- expectJust "second location file id"
- (locFileId (onlyAxiomLocation second))
- assertBool "relocation rebinds locations"
- (firstFileId /= secondFileId)
- firstArtifactKey <- expectRight
- (Semantic.moduleArtifactKey
- (Module.moduleName (Parse.parsedModuleAddress first))
- (Parse.parsedModuleId first)
- []
- theory)
- secondArtifactKey <- expectRight
- (Semantic.moduleArtifactKey
- (Module.moduleName (Parse.parsedModuleAddress second))
- (Parse.parsedModuleId second)
- []
- theory)
- assertBool "module artifact remains owner-dependent"
- (Semantic.moduleArtifactId firstArtifactKey
- /= Semantic.moduleArtifactId secondArtifactKey)
- Store.closeStore store
-
-rejectsCorruptedCachedDeclarationAnchor :: Assertion
-rejectsCorruptedCachedDeclarationAnchor =
- withTemporaryDirectory "felix-parsed-corrupt-anchor" \temp -> do
- writeBuiltinZeroDefinition
- (temp Posix.</> "entry.tex")
- "source_zero"
- mounts <- oneMount "project" temp
- request <- expectRight (searchedRoot "entry.tex")
- foundation <- expectRight Foundation.checkedFoundation
- let storePath = temp Posix.</> "store.sqlite"
- theory = Identity.theoryId foundation
- store <- openTestStore storePath theory
- cold <- expectParseExecution
- =<< Parse.parseSourceWorkspaceWithStoreAndSyntaxInputs
- store mounts request (const [])
- let parsed = Parse.parsedWorkspaceRootModule cold
- key = Parse.parsedModuleKey parsed
- fileId <- case Parse.parsedModuleSyntaxOccurrences parsed of
- occurrence : _ ->
- expectJust
- "parsed occurrence file id"
- (locFileId
- (Parse.parsedSyntaxOccurrenceLocation occurrence))
- [] ->
- assertFailure "parsed fixed occurrence is absent"
- >> fail "unreachable"
- decoded <- expectRight
- (Parsed.decodeCanonicalParsedPayload
- fileId
- (Parse.parsedModulePayload parsed))
- Store.closeStore store
- let corruptedOccurrences = case Parsed.decodedParsedOccurrences decoded of
- (blockIndex, location, _marker, entry) : rest ->
- (blockIndex, location, "corrupted_anchor", entry) : rest
- [] ->
- []
- corruptedPayload =
- Parsed.canonicalParsedPayload
- (Parsed.decodedParsedImports decoded)
- (Parsed.decodedParsedBlocks decoded)
- corruptedOccurrences
- (Parsed.decodedParsedSyntaxInterface decoded)
- corruptedId =
- ParsedIdentity.parsedModuleId
- key
- (Parsed.canonicalParsedPayloadBytes corruptedPayload)
- connection <- SQLite.open storePath
- SQLite.execute connection
- "UPDATE parsed_artifacts \
- \SET parsed_module_id = ?, payload = ? \
- \WHERE parsed_module_key = ?"
- ( Cache.cacheDigestBytes
- (ParsedIdentity.parsedModuleIdDigest corruptedId)
- , Parsed.canonicalParsedPayloadBytes corruptedPayload
- , Cache.cacheDigestBytes
- (ParsedIdentity.parsedModuleKeyDigest key)
- )
- SQLite.close connection
- current <- openTestStore storePath theory
- callbacks <- newIORef (0 :: Int)
- Parse.parseSourceWorkspaceWithStoreAndSyntaxInputsAndCallback
- current mounts request (const [])
- (\_source _block -> modifyIORef' callbacks (+ 1)) >>= \case
- Left
- (Parse.ParseExecutionArtifactIntegrityFailure
- _source
- (Parse.ParsedArtifactAssociationFailure
- Parse.SyntaxOccurrenceMarkerMismatch{})) ->
- pure ()
- other ->
- assertFailure
- ("unexpected corrupted parsed result: " <> show other)
- assertEqual "corrupt hit invokes no parse callback" 0
- =<< readIORef callbacks
- Store.closeStore current
-
-openTestStore :: FilePath -> Identity.TheoryId -> IO Store.Store
-openTestStore path theory =
- Store.openStore path theory >>= \case
- Left failure ->
- assertFailure (show failure) >> fail "unreachable"
- Right (_startup, store) ->
- pure store
-
-expectParseExecution
- :: Either Parse.ParseExecutionError value
- -> IO value
-expectParseExecution = \case
- Left failure ->
- assertFailure (show failure) >> fail "unreachable"
- Right value ->
- pure value
-
-parsesSourceGraph :: Assertion
-parsesSourceGraph =
- withTemporaryDirectory "felix-source-parse" \temp -> do
- writeTheory (temp Posix.</> "shared.tex") [] "shared"
- writeTheory (temp Posix.</> "entry.tex") ["shared.tex"] "entry"
- graph <- buildSearchedGraph temp "entry.tex"
- emittedRef <- newIORef []
- workspace <- expectRight =<<
- Parse.parseResolvedSourceGraphWith graph
- (\source _block ->
- modifyIORef'
- emittedRef
- (safeRelativePathFilePath
- (resolvedSourceRelativePath source) :))
- assertEqual "two parsed source nodes" 2
- (length (Parse.parsedWorkspaceModules workspace))
- assertEqual "one source-local block per node" [1, 1]
- (toList
- (length . Parse.parsedModuleBlocks
- <$> Parse.parsedWorkspaceImportedBeforeImporter workspace))
- assertEqual "imported-before-importer source order"
- ["shared.tex", "entry.tex"]
- (toList
- (safeRelativePathFilePath
- . resolvedSourceRelativePath
- . Parse.parsedModuleResolved
- <$> Parse.parsedWorkspaceImportedBeforeImporter workspace))
- assertEqual "flattened block view" 2
- (length (Parse.importedBeforeImporterBlocks workspace))
- emitted <- reverse <$> readIORef emittedRef
- assertEqual "streamed block order"
- ["shared.tex", "entry.tex"]
- emitted
-
-rejectsSiblingSyntaxLeakage :: Assertion
-rejectsSiblingSyntaxLeakage =
- withTemporaryDirectory "felix-source-syntax-world" \temp -> do
- writeFile
- (temp Posix.</> "use.tex")
- (unlines
- [ "\\begin{axiom}\\label{use}"
- , " $x$ is special."
- , "\\end{axiom}"
- ])
- writeAdjectiveDefinition
- (temp Posix.</> "declare.tex")
- "shared_special"
- writeTheory
- (temp Posix.</> "entry.tex")
- ["use.tex", "declare.tex"]
- "entry"
- graph <- buildSearchedGraph temp "entry.tex"
- result <- Parse.parseResolvedSourceGraph graph
- case result of
- Left (Parse.SourceParseError source _parseError) ->
- assertEqual
- "syntax consumer fails in its own module"
- "use.tex"
- (safeRelativePathFilePath
- (resolvedSourceRelativePath source))
- Left err ->
- assertFailure
- ("expected a source-local parse error, got "
- <> show err)
- Right workspace ->
- assertFailure
- ("sibling syntax leaked into use.tex: "
- <> show workspace)
-
-parsesSourceFixities :: Assertion
-parsesSourceFixities =
- withTemporaryDirectory "felix-source-fixity" \temp -> do
- writeFile
- (temp Posix.</> "entry.tex")
- ( syntaxFunctionDefinition
- "loose"
- "loose"
- (Just "%! infixl 0")
- <> syntaxFunctionDefinition
- "tight"
- "tight"
- (Just "%! infixr 7")
- <> axiomBlock
- "loose_associativity"
- "a\\loose b\\loose c = a"
- <> axiomBlock
- "tight_associativity"
- "a\\tight b\\tight c = a"
- <> axiomBlock
- "mixed_precedence"
- "a\\loose b\\tight c = a"
- <> axiomBlock
- "parenthesized_precedence"
- "(a\\loose b)\\tight c = a"
- )
- graph <- buildSearchedGraph temp "entry.tex"
- workspace <- expectRight
- =<< Parse.parseResolvedSourceGraph graph
- let root =
- Parse.parsedWorkspaceRootModule workspace
- localEntries =
- Interface.canonicalSyntaxDeltaEntries
- (Interface.moduleSyntaxLocalDelta
- (Parse.parsedModuleSyntaxInterface root))
- assertExpressionFixity
- "loose"
- Raw.LeftAssoc
- 0
- localEntries
- assertExpressionFixity
- "tight"
- Raw.RightAssoc
- 7
- localEntries
- assertEqual
- "source declaration occurrences"
- [0, 1]
- (Parse.parsedSyntaxOccurrenceBlockIndex
- <$> Parse.parsedModuleSyntaxOccurrences root)
- case drop 2 (Parse.parsedModuleBlocks root) of
- [ looseAssociativity
- , tightAssociativity
- , mixedPrecedence
- , parenthesizedPrecedence
- ] -> do
- assertAxiomLeftShape
- "left associativity"
- "loose(loose(a,b),c)"
- looseAssociativity
- assertAxiomLeftShape
- "right associativity"
- "tight(a,tight(b,c))"
- tightAssociativity
- assertAxiomLeftShape
- "mixed precedence"
- "loose(a,tight(b,c))"
- mixedPrecedence
- assertAxiomLeftShape
- "parentheses override precedence"
- "tight(loose(a,b),c)"
- parenthesizedPrecedence
- blocks ->
- assertFailure
- ("expected four fixity axioms, got "
- <> show blocks)
-
-parsesLibraryFixities :: Assertion
-parsesLibraryFixities =
- withTemporaryDirectory "felix-source-library-fixity" \temp -> do
- writeFile
- (temp Posix.</> "entry.tex")
- ( syntaxFunctionDefinition
- "cdot"
- "cdot"
- (Just "%! infixl 4")
- <> syntaxFunctionDefinition
- "symdiff"
- "symdiff"
- (Just "%! infixl 1")
- <> axiomBlock
- "cdot_associativity"
- "a\\cdot b\\cdot c = a"
- <> axiomBlock
- "symdiff_associativity"
- "a\\symdiff b\\symdiff c = a"
- <> axiomBlock
- "library_mixed_precedence"
- "a\\symdiff b\\cdot c = a"
- <> axiomBlock
- "library_parentheses"
- "(a\\symdiff b)\\cdot c = a"
- )
- graph <- buildSearchedGraph temp "entry.tex"
- workspace <- expectRight
- =<< Parse.parseResolvedSourceGraph graph
- case drop 2
- (Parse.parsedModuleBlocks
- (Parse.parsedWorkspaceRootModule workspace)) of
- [ cdotAssociativity
- , symdiffAssociativity
- , mixedPrecedence
- , parenthesizedPrecedence
- ] -> do
- assertAxiomLeftShape
- "cdot left associativity"
- "cdot(cdot(a,b),c)"
- cdotAssociativity
- assertAxiomLeftShape
- "symdiff left associativity"
- "symdiff(symdiff(a,b),c)"
- symdiffAssociativity
- assertAxiomLeftShape
- "cdot binds tighter than symdiff"
- "symdiff(a,cdot(b,c))"
- mixedPrecedence
- assertAxiomLeftShape
- "library parentheses override precedence"
- "cdot(symdiff(a,b),c)"
- parenthesizedPrecedence
- blocks ->
- assertFailure
- ("expected four library-fixity axioms, got "
- <> show blocks)
-
-validatesSourcePragmaAssociations :: Assertion
-validatesSourcePragmaAssociations =
- forM_ cases \(description, contents, checkProblem) ->
- withTemporaryDirectory
- ("felix-source-pragma-" <> description)
- \temp -> do
- writeFile
- (temp Posix.</> "entry.tex")
- contents
- graph <- buildSearchedGraph temp "entry.tex"
- result <- Parse.parseResolvedSourceGraph graph
- case result of
- Left
- (Parse.SourceSyntaxDeclarationError
- source
- problem) -> do
- assertEqual
- "pragma source"
- "entry.tex"
- (safeRelativePathFilePath
- (resolvedSourceRelativePath source))
- checkProblem problem
- Left err ->
- assertFailure
- ("expected source pragma error, got "
- <> show err)
- Right workspace ->
- assertFailure
- ("expected source pragma rejection, got "
- <> show workspace)
- where
- cases
- :: [ ( String
- , String
- , Parse.SyntaxDeclarationError -> Assertion
- )
- ]
- cases =
- [ ( "outside"
- , "%! infixl 1\n" <> theoryBlock "outside"
- , \case
- Parse.SyntaxPragmaOutsideDeclaration{} ->
- pure ()
- problem ->
- unexpected "outside-declaration pragma" problem
- )
- , ( "inside-nonsyntax"
- , unlines
- [ "\\begin{axiom}\\label{inside_nonsyntax}"
- , " %! infixl 1"
- , " $x = x$."
- , "\\end{axiom}"
- ]
- , \case
- Parse.SyntaxPragmaOutsideDeclaration location ->
- assertEqual
- "pragma in non-syntax chunk"
- 2
- (locLine location)
- problem ->
- unexpected "non-syntax declaration pragma" problem
- )
- , ( "missing"
- , syntaxFunctionDefinition
- "missing"
- "missing"
- Nothing
- , \case
- Parse.MissingSyntaxPragma{} ->
- pure ()
- problem ->
- unexpected "missing pragma" problem
- )
- , ( "duplicate"
- , unlines
- [ "\\begin{abbreviation}\\label{duplicate}"
- , " %! infixl 1"
- , " %! infixl 1"
- , " $x\\duplicate y = x$."
- , "\\end{abbreviation}"
- ]
- , \case
- Parse.DuplicateSyntaxPragma{} ->
- pure ()
- problem ->
- unexpected "duplicate pragma" problem
- )
- , ( "irrelevant"
- , unlines
- [ "\\begin{definition}\\label{irrelevant}"
- , " %! infixl 1"
- , " $x$ is irrelevant iff $x = x$."
- , "\\end{definition}"
- ]
- , \case
- Parse.IrrelevantSyntaxPragma{} ->
- pure ()
- problem ->
- unexpected "irrelevant pragma" problem
- )
- , ( "multiple-without-pragma"
- , unlines
- [ "\\begin{datatype}\\label{multiple_patterns}"
- , " Define $\\patternkind$ inductively as follows."
- , " \\begin{enumerate}"
- , " \\item $(x \\firstpattern y) \\in \\patternkind$."
- , " \\item $(x \\secondpattern y) \\in \\patternkind$."
- , " \\end{enumerate}"
- , "\\end{datatype}"
- ]
- , \case
- problem@(Parse.MultipleNewSyntaxPatternsWithoutPragma
- location
- patterns) -> do
- assertEqual
- "first new pattern location"
- 4
- (locLine location)
- assertEqual
- "new pattern count"
- 2
- (NonEmpty.length patterns)
- assertBool
- "accurate multiple-pattern message"
- ("several new eligible patterns that V1 cannot select between"
- `List.isInfixOf` show problem)
- assertBool
- "message requires an unambiguous declaration"
- ("make the declaration unambiguous"
- `List.isInfixOf` show problem)
- problem ->
- unexpected "multiple unannotated patterns" problem
- )
- , ( "fixed"
- , unlines
- [ "\\begin{abbreviation}\\label{local_addition}"
- , " %! infixl 1"
- , " $x + y = x$."
- , "\\end{abbreviation}"
- ]
- , \case
- Parse.SyntaxPragmaOnFixedReuse{} ->
- pure ()
- problem ->
- unexpected "fixed-base pragma" problem
- )
- ]
-
- unexpected expected problem =
- assertFailure
- ("expected " <> expected <> ", got " <> show problem)
-
-rejectsFixedBaseCategoryMismatch :: Assertion
-rejectsFixedBaseCategoryMismatch =
- withTemporaryDirectory "felix-source-fixed-category" \temp -> do
- writeFile
- (temp Posix.</> "entry.tex")
- (unlines
- [ "\\begin{definition}\\label{local_add_relation}"
- , " $x + y$ iff $x = y$."
- , "\\end{definition}"
- ])
- graph <- buildSearchedGraph temp "entry.tex"
- collision <- expectLexiconCollision
- =<< Parse.parseResolvedSourceGraph graph
- assertEqual
- "fixed collision pattern"
- (Raw.HoleCons
- (Raw.TokenCons
- (Raw.Symbol "+")
- (Raw.HoleCons Raw.End)))
- (Parse.lexiconCollisionPattern collision)
- case toList (Parse.lexiconCollisionOrigins collision) of
- [ Parse.FixedLexiconOrigin
- Interface.CanonicalExpressionFunction{}
- , Parse.SourceLexiconOrigin
- Interface.CanonicalRelation{}
- source
- location
- ] -> do
- assertEqual
- "local collision source"
- "entry.tex"
- (safeRelativePathFilePath
- (resolvedSourceRelativePath source))
- assertLocation
- "local collision declaration"
- "entry.tex"
- 1
- location
- origins ->
- assertFailure
- ("expected fixed/source category origins, got "
- <> show origins)
-
-retainsMultiItemSyntaxOccurrences :: Assertion
-retainsMultiItemSyntaxOccurrences =
- withTemporaryDirectory "felix-source-multi-item-syntax" \temp -> do
- writeFile
- (temp Posix.</> "entry.tex")
- (unlines
- [ "\\begin{datatype}\\label{multi_item}"
- , " Define $\\itemkind$ inductively as follows."
- , " \\begin{enumerate}"
- , " \\item $\\itemzero \\in \\itemkind$."
- , " \\item $\\itemsucc{x} \\in \\itemkind$ for $x \\in \\itemkind$."
- , " \\end{enumerate}"
- , "\\end{datatype}"
- ])
- graph <- buildSearchedGraph temp "entry.tex"
- workspace <- expectRight
- =<< Parse.parseResolvedSourceGraph graph
- let root =
- Parse.parsedWorkspaceRootModule workspace
- occurrences =
- Parse.parsedModuleSyntaxOccurrences root
- summarize occurrence =
- case Parse.parsedSyntaxOccurrenceEntry occurrence of
- Interface.CanonicalExpressionFunction
- _pattern
- marker
- _fixity ->
- Right
- ( Parse.parsedSyntaxOccurrenceBlockIndex
- occurrence
- , locLine
- (Parse.parsedSyntaxOccurrenceLocation
- occurrence)
- , Parse.parsedSyntaxOccurrenceMarker occurrence
- , marker
- )
- entry ->
- Left entry
- case traverse summarize occurrences of
- Right summaries ->
- assertEqual
- "block association and scanner order"
- [ (0, 2, "multi_item", "multi_item")
- , (0, 4, "itemzero", "itemzero")
- , (0, 5, "itemsucc", "itemsucc")
- ]
- summaries
- Left entry ->
- assertFailure
- ("expected an expression occurrence, got "
- <> show entry)
- case (Parse.parsedModuleBlocks root, occurrences) of
- ( Raw.BlockData _location _title blockMarker _datatype : _
- , firstOccurrence : _
- ) ->
- assertEqual
- "first occurrence is the declaration-head anchor"
- blockMarker
- (Parse.parsedSyntaxOccurrenceMarker firstOccurrence)
- _ ->
- assertFailure "expected a datatype block and its occurrences"
-
-propagatesImportedSyntax :: Assertion
-propagatesImportedSyntax =
- withTemporaryDirectory "felix-source-syntax-diamond" \temp -> do
- writeFile
- (temp Posix.</> "base.tex")
- (syntaxFunctionDefinition
- "star"
- "star"
- (Just "%! infixl 3"))
- writeFile
- (temp Posix.</> "left.tex")
- ("\\import{base.tex}\n"
- <> syntaxFunctionDefinition
- "star"
- "star"
- Nothing)
- writeTheory
- (temp Posix.</> "right.tex")
- ["base.tex"]
- "right"
- writeFile
- (temp Posix.</> "entry.tex")
- (unlines
- [ "\\import{left.tex}"
- , "\\import{right.tex}"
- ]
- <> axiomBlock
- "imported_use"
- "a\\star b\\star c = a")
- graph <- buildSearchedGraph temp "entry.tex"
- workspace <- expectRight
- =<< Parse.parseResolvedSourceGraph graph
- baseModule <- findParsedModule "base.tex" workspace
- leftModule <- findParsedModule "left.tex" workspace
- rightModule <- findParsedModule "right.tex" workspace
- let root =
- Parse.parsedWorkspaceRootModule workspace
- interface =
- Parse.parsedModuleSyntaxInterface
- localEntries parsed =
- Interface.canonicalSyntaxDeltaEntries
- (Interface.moduleSyntaxLocalDelta
- (interface parsed))
- assertEqual "base exports one syntax entry"
- 1
- (length (localEntries baseModule))
- assertEqual "imported reuse emits no local entry"
- []
- (localEntries leftModule)
- assertEqual "imported reuse retains its occurrence"
- 1
- (length
- (Parse.parsedModuleSyntaxOccurrences leftModule))
- assertEqual "empty diamond branch has no occurrence"
- []
- (Parse.parsedModuleSyntaxOccurrences rightModule)
- assertEqual "equal diamond interfaces"
- (Interface.moduleSyntaxAssertedId
- (interface leftModule))
- (Interface.moduleSyntaxAssertedId
- (interface rightModule))
- assertEqual "root coalesces equal direct interfaces"
- 1
- (length
- (Interface.moduleSyntaxDirectInputs
- (interface root)))
- case Parse.parsedModuleBlocks root of
- [block] ->
- assertAxiomLeftShape
- "imported left associativity"
- "star(star(a,b),c)"
- block
- blocks ->
- assertFailure
- ("expected one imported-syntax axiom, got "
- <> show blocks)
- writeFile
- (temp Posix.</> "left.tex")
- ("\\import{base.tex}\n"
- <> syntaxFunctionDefinition
- "star"
- "star"
- (Just "%! infixl 3"))
- reuseGraph <- buildSearchedGraph temp "left.tex"
- reuseResult <-
- Parse.parseResolvedSourceGraph reuseGraph
- case reuseResult of
- Left
- (Parse.SourceSyntaxDeclarationError
- _source
- Parse.SyntaxPragmaOnImportedReuse{}) ->
- pure ()
- Left err ->
- assertFailure
- ("expected imported-reuse pragma rejection, got "
- <> show err)
- Right reused ->
- assertFailure
- ("expected imported-reuse pragma rejection, got "
- <> show reused)
-
-rejectsUnequalImportedSyntax :: Assertion
-rejectsUnequalImportedSyntax =
- forM_ cases \(description, leftDefinition, rightDefinition) ->
- withTemporaryDirectory
- ("felix-source-imported-collision-" <> description)
- \temp -> do
- writeFile
- (temp Posix.</> "a.tex")
- leftDefinition
- writeFile
- (temp Posix.</> "b.tex")
- rightDefinition
- writeTheory
- (temp Posix.</> "entry.tex")
- ["a.tex", "b.tex"]
- "entry"
- graph <- buildSearchedGraph temp "entry.tex"
- collision <- expectLexiconCollision
- =<< Parse.parseResolvedSourceGraph graph
- (firstLocation, secondLocation) <-
- expectTwoCollisionLocations collision
- assertLocation
- "first imported declaration"
- "a.tex"
- 1
- firstLocation
- assertLocation
- "second imported declaration"
- "b.tex"
- 1
- secondLocation
- where
- cases =
- [ ( "marker"
- , syntaxFunctionDefinition
- "clash_left"
- "clash"
- (Just "%! infixl 2")
- , syntaxFunctionDefinition
- "clash_right"
- "clash"
- (Just "%! infixl 2")
- )
- , ( "fixity"
- , syntaxFunctionDefinition
- "clash"
- "clash"
- (Just "%! infixl 2")
- , syntaxFunctionDefinition
- "clash"
- "clash"
- (Just "%! infixr 2")
- )
- ]
-
-distinguishesPhysicalSourceLocations :: Assertion
-distinguishesPhysicalSourceLocations =
- withTemporaryDirectory "felix-source-location-identity" \temp -> do
- let projectRoot = temp Posix.</> "project"
- libraryRoot = temp Posix.</> "library"
- projectEntry = projectRoot Posix.</> "entry.tex"
- libraryEntry = libraryRoot Posix.</> "entry.tex"
- Directory.createDirectory projectRoot
- Directory.createDirectory libraryRoot
- writeFile projectEntry
- ("\\import{entry.tex}\n"
- <> adjectiveDefinition "project_adjective")
- writeNounDefinition libraryEntry "library_noun"
- mounts <- expectRight =<< prepareSourceMounts
- [ (sourceMountId "library", libraryRoot)
- , (sourceMountId "project", projectRoot)
- ]
- request <- expectRight =<< existingRoot projectEntry
- graph <- expectRight =<< buildResolvedSourceGraph mounts request
- collision <- expectLexiconCollision
- =<< Parse.parseResolvedSourceGraph graph
- assertEqual "normalized cross-category pattern"
- (Raw.TokenCons (Raw.Word "special") Raw.End)
- (Parse.lexiconCollisionPattern collision)
- (libraryLocation, projectLocation) <-
- expectTwoCollisionLocations collision
- assertEqual "accepted display path"
- "entry.tex"
- (locFile libraryLocation)
- assertEqual "accepted declaration line"
- 1
- (locLine libraryLocation)
- assertEqual "colliding display path"
- "entry.tex"
- (locFile projectLocation)
- assertEqual "colliding declaration line"
- 2
- (locLine projectLocation)
- canonicalProject <- Directory.canonicalizePath projectEntry
- canonicalLibrary <- Directory.canonicalizePath libraryEntry
- let rendered = show collision
- quotedLibrary = show canonicalLibrary
- quotedProject = show canonicalProject
- assertBool "rendered error includes accepted canonical path"
- (quotedLibrary `List.isInfixOf` rendered)
- assertBool "rendered error includes colliding canonical path"
- (quotedProject `List.isInfixOf` rendered)
- assertBool "canonical locations render in declaration order"
- (substringIndex quotedLibrary rendered
- < substringIndex quotedProject rendered)
-
-retainsWorkspaceLocationDisplayPath :: Assertion
-retainsWorkspaceLocationDisplayPath =
- withTemporaryDirectory "felix-source-location-display" \temp -> do
- let nested = temp Posix.</> "nested"
- entry = nested Posix.</> "entry.tex"
- Directory.createDirectory nested
- writeTheory entry [] "entry"
- outerMounts <- oneMount "project" temp
- outerRequest <- expectRight (searchedRoot "nested/entry.tex")
- outerGraph <- expectRight =<<
- buildResolvedSourceGraph outerMounts outerRequest
- outerWorkspace <- expectRight =<<
- Parse.parseResolvedSourceGraph outerGraph
- innerMounts <- oneMount "library" nested
- innerRequest <- expectRight (searchedRoot "entry.tex")
- innerGraph <- expectRight =<<
- buildResolvedSourceGraph innerMounts innerRequest
- innerWorkspace <- expectRight =<<
- Parse.parseResolvedSourceGraph innerGraph
- let outerLocation =
- onlyAxiomLocation
- (Parse.parsedWorkspaceRootModule outerWorkspace)
- innerLocation =
- onlyAxiomLocation
- (Parse.parsedWorkspaceRootModule innerWorkspace)
- assertEqual "outer-mount display path"
- "nested/entry.tex"
- (locFile outerLocation)
- assertEqual "more-specific-mount display path"
- "entry.tex"
- (locFile innerLocation)
- outerFileId <- expectJust "outer workspace file id"
- (locFileId outerLocation)
- innerFileId <- expectJust "inner workspace file id"
- (locFileId innerLocation)
- assertBool "distinct display registrations use distinct file ids"
- (outerFileId /= innerFileId)
- canonicalEntry <- Directory.canonicalizePath entry
- assertEqual "outer physical location key"
- (Just canonicalEntry)
- (lookupFileIdentityPath outerFileId)
- assertEqual "inner physical location key"
- (Just canonicalEntry)
- (lookupFileIdentityPath innerFileId)
-
-reportsImportedScannerErrorFirst :: Assertion
-reportsImportedScannerErrorFirst =
- withTemporaryDirectory "felix-source-lexer-error-order" \temp -> do
- let scannerFailure = unlines
- [ "\\begin{abbreviation}\\label{malformed_function}"
- , " $x = \\emptyset$."
- , "\\end{abbreviation}"
- ]
- tokenizerFailure = unlines
- [ "\\begin{axiom}"
- , "#"
- , "\\end{axiom}"
- ]
- writeFile
- (temp Posix.</> "imported.tex")
- scannerFailure
- writeFile
- (temp Posix.</> "entry.tex")
- ("\\import{imported.tex}\n" <> tokenizerFailure)
- graph <- buildSearchedGraph temp "entry.tex"
- result <- Parse.parseResolvedSourceGraph graph
- case result of
- Left
- (Parse.SourceParseError
- source
- (Parse.LexicalScanFailure
- Adapt.InvalidFunctionPattern{})) ->
- assertEqual
- "dependency scanner error"
- "imported.tex"
- (safeRelativePathFilePath
- (resolvedSourceRelativePath source))
- Left err ->
- assertFailure
- ("expected imported scanner error, got " <> show err)
- Right workspace ->
- assertFailure
- ("expected imported scanner error, got "
- <> show workspace)
-
-reportsMalformedLexicalDeclaration :: Assertion
-reportsMalformedLexicalDeclaration =
- withTemporaryDirectory "felix-source-malformed-lexical" \temp -> do
- writeFile
- (temp Posix.</> "entry.tex")
- (unlines
- [ "\\begin{abbreviation}\\label{malformed_function}"
- , " $x = \\emptyset$."
- , "\\end{abbreviation}"
- ])
- graph <- buildSearchedGraph temp "entry.tex"
- result <- Parse.parseResolvedSourceGraph graph
- void (evaluate (length (show result)))
- case result of
- Left
- (Parse.SourceParseError
- source
- (Parse.LexicalScanFailure
- (Adapt.InvalidFunctionPattern
- location
- Adapt.FunctionPatternBareVariable))) -> do
- assertEqual "malformed source"
- "entry.tex"
- (safeRelativePathFilePath
- (resolvedSourceRelativePath source))
- assertLocation
- "malformed declaration"
- "entry.tex"
- 1
- location
- Left err ->
- assertFailure
- ("expected typed lexical scan failure, got " <> show err)
- Right workspace ->
- assertFailure
- ("expected typed lexical scan failure, got "
- <> show workspace)
-
-rejectsMalformedInductivePattern :: Assertion
-rejectsMalformedInductivePattern =
- case runLexer (FileId 0) "inductive.tex" source of
- Left err ->
- assertFailure ("could not tokenize fixture: " <> show err)
- Right (_imports, [chunk]) ->
- case Adapt.scanChunk chunk of
- Left
- (Adapt.InvalidFunctionPattern
- _location
- Adapt.FunctionPatternBareVariable) ->
- pure ()
- Left err ->
- assertFailure
- ("expected bare-variable scan failure, got "
- <> show err)
- Right scans ->
- assertFailure
- ("expected bare-variable scan failure, got "
- <> show scans)
- Right (_imports, chunks) ->
- assertFailure
- ("expected one lexical chunk, got " <> show (length chunks))
- where
- source =
- Text.pack
- (unlines
- [ "\\begin{inductive}\\label{malformed_inductive}"
- , " Define $x\\subseteq\\pow{x}$ inductively."
- , "\\end{inductive}"
- ])
-
-acceptsAdjectiveSignature :: Assertion
-acceptsAdjectiveSignature =
- withTemporaryDirectory "felix-source-signature-adjective" \temp -> do
- writeFile
- (temp Posix.</> "entry.tex")
- (unlines
- [ "\\begin{signature}\\label{reflexive_signature}"
- , " Suppose $A$ is a set."
- , " Then $x$ can be reflexive."
- , "\\end{signature}"
- , "\\begin{axiom}\\label{reflexive_use}"
- , " $x$ is reflexive."
- , "\\end{axiom}"
- ])
- graph <- buildSearchedGraph temp "entry.tex"
- workspace <- expectRight
- =<< Parse.parseResolvedSourceGraph graph
- let blocks = Parse.importedBeforeImporterBlocks workspace
- case blocks of
- [ Raw.BlockSig
- _signatureLocation
- _signatureTitle
- _signatureMarker
- [_signatureAssumption]
- (Raw.SignatureAdj
- _variable
- (Raw.Adj _adjectiveLocation declaredAdjective []))
- , Raw.BlockAxiom{}
- ] -> do
- assertEqual
- "signature marker enters the lexicon"
- "reflexive_signature"
- (Raw.lexicalItemMarker declaredAdjective)
- _ ->
- assertFailure
- ("unexpected adjective-signature blocks: " <> show blocks)
-
-rejectsMalformedSignatureHead :: Assertion
-rejectsMalformedSignatureHead = do
- case runLexer
- (FileId 49)
- "malformed-signature.tex"
- (Text.unlines
- [ "\\begin{signature}\\label{bad_signature}"
- , " $x$ can be."
- , "\\end{signature}"
- ]) of
- Left err ->
- assertFailure ("unexpected token error: " <> show err)
- Right (_imports, [chunk]) ->
- case Adapt.scanChunk chunk of
- Left
- (Adapt.InvalidFunctionPattern
- location
- Adapt.FunctionPatternBareVariable) -> do
- assertEqual "error line" 1 (locLine location)
- assertEqual "error column" 1 (locColumn location)
- Left err ->
- assertFailure
- ("expected malformed signature error, got " <> show err)
- Right scans ->
- assertFailure
- ("expected malformed signature rejection, got "
- <> show scans)
- Right (_imports, chunks) ->
- assertFailure
- ("expected one malformed signature chunk, got "
- <> show (length chunks))
-
-reportsSameSourceLexiconCollision :: Assertion
-reportsSameSourceLexiconCollision =
- withTemporaryDirectory "felix-source-local-lexicon-collision" \temp -> do
- writeFile
- (temp Posix.</> "entry.tex")
- (unlines
- [ "\\begin{struct}\\label{duplicate_operations}"
- , " A \\duplicateop $X$ is equipped with"
- , " \\begin{enumerate}"
- , " \\item $\\duplicateop$"
- , " \\end{enumerate}"
- , "\\end{struct}"
- ])
- graph <- buildSearchedGraph temp "entry.tex"
- collision <- expectLexiconCollision
- =<< Parse.parseResolvedSourceGraph graph
- (firstLocation, secondLocation) <-
- expectTwoCollisionLocations collision
- assertEqual "first declaration file"
- "entry.tex"
- (locFile firstLocation)
- assertEqual "first declaration line" 1 (locLine firstLocation)
- assertEqual "colliding declaration file"
- "entry.tex"
- (locFile secondLocation)
- assertEqual "colliding declaration line" 4 (locLine secondLocation)
- assertBool "declarations have distinct locations"
- (firstLocation /= secondLocation)
-
-acceptsBuiltinSourceDeclaration :: Assertion
-acceptsBuiltinSourceDeclaration =
- withTemporaryDirectory "felix-source-builtin-declaration" \temp -> do
- writeBuiltinZeroDefinition
- (temp Posix.</> "entry.tex")
- "source_zero"
- graph <- buildSearchedGraph temp "entry.tex"
- workspace <- expectRight
- =<< Parse.parseResolvedSourceGraph graph
- let root =
- Parse.parsedWorkspaceRootModule workspace
- assertEqual
- "fixed reuse emits no local syntax"
- []
- (Interface.canonicalSyntaxDeltaEntries
- (Interface.moduleSyntaxLocalDelta
- (Parse.parsedModuleSyntaxInterface root)))
- case Parse.parsedModuleBlocks root of
- [Raw.BlockAbbr
- _location
- _title
- blockMarker
- (Raw.AbbreviationEq
- (Raw.SymbolPattern
- (Raw.MixfixItem
- _pattern
- symbolMarker
- _associativity)
- [])
- _expression)] -> do
- assertEqual
- "declaration label remains independent"
- "source_zero"
- blockMarker
- assertEqual
- "built-in marker remains authoritative"
- "zero"
- symbolMarker
- case Parse.parsedModuleSyntaxOccurrences root of
- [occurrence] ->
- case Parse.parsedSyntaxOccurrenceEntry occurrence of
- Interface.CanonicalExpressionFunction
- _pattern
- occurrenceMarker
- _fixity -> do
- assertEqual
- "occurrence retains source marker"
- "source_zero"
- (Parse.parsedSyntaxOccurrenceMarker
- occurrence)
- assertEqual
- "occurrence uses fixed marker"
- "zero"
- occurrenceMarker
- fileId <- expectJust
- "fixed occurrence file id"
- (locFileId
- (Parse.parsedSyntaxOccurrenceLocation
- occurrence))
- decoded <- expectRight
- (Parsed.decodeCanonicalParsedPayload
- fileId
- (Parse.parsedModulePayload root))
- case Parsed.decodedParsedOccurrences decoded of
- [ ( _blockIndex
- , _location
- , storedMarker
- , Interface.CanonicalExpressionFunction
- _storedPattern
- storedEntryMarker
- _storedFixity
- )
- ] -> do
- assertEqual
- "payload source marker"
- "source_zero"
- storedMarker
- assertEqual
- "payload authoritative marker"
- "zero"
- storedEntryMarker
- stored ->
- assertFailure
- ("unexpected decoded fixed occurrence: "
- <> show stored)
- entry ->
- assertFailure
- ("unexpected fixed occurrence: "
- <> show entry)
- occurrences ->
- assertFailure
- ("unexpected fixed occurrences: "
- <> show occurrences)
- blocks ->
- assertFailure
- ("unexpected built-in declaration parse: "
- <> show blocks)
-
-acceptsBuiltinPrefixPredicateDeclaration :: Assertion
-acceptsBuiltinPrefixPredicateDeclaration =
- withTemporaryDirectory "felix-source-builtin-prefix" \temp -> do
- writeBuiltinCongDefinition
- (temp Posix.</> "entry.tex")
- graph <- buildSearchedGraph temp "entry.tex"
- workspace <- expectRight
- =<< Parse.parseResolvedSourceGraph graph
- case Parse.parsedModuleBlocks
- (Parse.parsedWorkspaceRootModule workspace) of
- [Raw.BlockDefn
- _location
- _title
- _blockMarker
- (Raw.Defn
- _assumptions
- (Raw.DefnSymbolicPredicate
- predicate
- predicateMarker
- _variables)
- _statement)] -> do
- assertEqual "built-in prefix predicate"
- (Raw.PrefixPredicate "Cong" 4)
- predicate
- assertEqual
- "built-in prefix marker remains authoritative"
- "cong"
- predicateMarker
- blocks ->
- assertFailure
- ("unexpected built-in prefix declaration parse: "
- <> show blocks)
-
-avoidsAliasImportLexiconCollision :: Assertion
-avoidsAliasImportLexiconCollision =
- withTemporaryDirectory "felix-source-alias-lexicon" \temp -> do
- let shared = temp Posix.</> "shared.tex"
- alias = temp Posix.</> "alias.tex"
- writeAdjectiveDefinition shared "shared_special"
- Directory.createFileLink shared alias
- writeFile
- (temp Posix.</> "entry.tex")
- (unlines
- [ "\\import{shared.tex}"
- , "\\import{shared.tex}"
- , "\\import{alias.tex}"
- , "\\begin{axiom}\\label{root}"
- , " $x$ is special."
- , "\\end{axiom}"
- ])
- graph <- buildSearchedGraph temp "entry.tex"
- workspace <- expectRight
- =<< Parse.parseResolvedSourceGraph graph
- assertEqual "canonical source is parsed once"
- ["shared.tex", "entry.tex"]
- (toList
- ( safeRelativePathFilePath
- . resolvedSourceRelativePath
- . Parse.parsedModuleResolved
- <$> Parse.parsedWorkspaceImportedBeforeImporter workspace
- ))
-
-parsesWithoutRereading :: Assertion
-parsesWithoutRereading =
- withTemporaryDirectory "felix-source-no-reread" \temp -> do
- let shared = temp Posix.</> "shared.tex"
- entry = temp Posix.</> "entry.tex"
- writeTheory shared [] "shared"
- writeTheory entry ["shared.tex"] "entry"
- graph <- buildSearchedGraph temp "entry.tex"
- Directory.removeFile entry
- Directory.removeFile shared
- firstWorkspace <- expectRight =<< Parse.parseResolvedSourceGraph graph
- secondWorkspace <- expectRight =<< Parse.parseResolvedSourceGraph graph
- assertEqual "first flat projection" 2
- (length (Parse.importedBeforeImporterBlocks firstWorkspace))
- assertEqual "repeated downstream projection" 2
- (length (Parse.importedBeforeImporterBlocks secondWorkspace))
-
-returnsSourceParseFailures :: Assertion
-returnsSourceParseFailures =
- withTemporaryDirectory "felix-source-parse-error" \temp -> do
- writeFile
- (temp Posix.</> "entry.tex")
- (theoryBlock "accepted"
- <> "\\begin{axiom}\\label{late_failure}\n")
- graph <- buildSearchedGraph temp "entry.tex"
- emittedRef <- newIORef []
- result <-
- Parse.parseResolvedSourceGraphWith graph
- (\_source block ->
- case block of
- Raw.BlockAxiom _location _title marker _axiom ->
- modifyIORef' emittedRef (marker :)
- _ ->
- assertFailure
- ("unexpected emitted block: " <> show block))
- case result of
- Left (Parse.SourceParseError source _err) -> do
- assertEqual "failed source" "entry.tex"
- (safeRelativePathFilePath
- (resolvedSourceRelativePath source))
- emitted <- reverse <$> readIORef emittedRef
- assertEqual "completed callbacks before later failure"
- ["accepted"]
- emitted
- Left err ->
- assertFailure ("expected SourceParseError, got " <> show err)
- Right workspace ->
- assertFailure ("expected parse failure, got " <> show workspace)
-
-rejectsGuardedSymbolicDeclarations :: Assertion
-rejectsGuardedSymbolicDeclarations =
- for_ [("definition", 3 :: Int), ("abbreviation", 2)]
- \(kind, failureLine) ->
- withTemporaryDirectory
- ("felix-guarded-symbolic-" <> kind)
- \temp -> do
- let relative = "entry.tex"
- source = unlines
- [ "\\begin{" <> kind <> "}\\label{guarded_symbolic}"
- , " Suppose $\\top$."
- , " $\\guardedsymbolic{X} = X$."
- , "\\end{" <> kind <> "}"
- ]
- writeFile (temp Posix.</> relative) source
- graph <- buildSearchedGraph temp relative
- emittedRef <- newIORef ([] :: [Raw.Block])
- result <-
- Parse.parseResolvedSourceGraphWith graph
- (\_source block -> modifyIORef' emittedRef (block :))
- case result of
- Left (Parse.SourceParseError failed parseFailure) -> do
- assertEqual (kind <> " source") relative
- (safeRelativePathFilePath
- (resolvedSourceRelativePath failed))
- assertBool
- (kind <> " parse failure retains a located source position: "
- <> show parseFailure)
- (("entry.tex " <> show failureLine <> ":")
- `List.isInfixOf` show parseFailure)
- assertEqual
- (kind <> " publishes no completed source block")
- []
- =<< readIORef emittedRef
- Left failure ->
- assertFailure
- ("expected guarded-symbolic parse failure, got "
- <> show failure)
- Right workspace ->
- assertFailure
- ("guarded symbolic " <> kind
- <> " was silently accepted: " <> show workspace)
-
-buildSearchedGraph :: FilePath -> FilePath -> IO ResolvedSourceGraph
-buildSearchedGraph root path = do
- mounts <- oneMount "project" root
- request <- expectRight (searchedRoot path)
- expectRight =<< buildResolvedSourceGraph mounts request
-
-sourceGraphOrderPaths :: ResolvedSourceGraph -> IO [FilePath]
-sourceGraphOrderPaths graph =
- pure
- [ safeRelativePathFilePath
- (resolvedSourceRelativePath (sourceNodeResolved node))
- | node <- toList (sourceGraphImportedBeforeImporter graph)
- ]
-
-sourceNodeCanonicalPathForTest :: SourceNode -> CanonicalPath
-sourceNodeCanonicalPathForTest =
- resolvedSourceCanonicalPath . sourceNodeResolved
-
-onlyAxiomLocation :: Parse.ParsedModule -> Location
-onlyAxiomLocation node =
- case Parse.parsedModuleBlocks node of
- [Raw.BlockAxiom location _title _marker _axiom] ->
- location
- blocks ->
- error ("expected one axiom block, got " <> show blocks)
-
-syntaxFunctionDefinition
- :: String
- -> String
- -> Maybe String
- -> String
-syntaxFunctionDefinition marker command pragma =
- unlines
- ( [ "\\begin{abbreviation}\\label{" <> marker <> "}"
- ]
- <> maybe [] (\line -> [" " <> line]) pragma
- <> [ " $x\\" <> command <> " y = x$."
- , "\\end{abbreviation}"
- ]
- )
-
-axiomBlock :: String -> String -> String
-axiomBlock marker statement =
- unlines
- [ "\\begin{axiom}\\label{" <> marker <> "}"
- , " $" <> statement <> "$."
- , "\\end{axiom}"
- ]
-
-assertExpressionFixity
- :: Text
- -> Raw.Associativity
- -> Word8
- -> [Interface.CanonicalLexicalEntry]
- -> Assertion
-assertExpressionFixity marker associativity level entries =
- case
- [ fixity
- | Interface.CanonicalExpressionFunction
- _pattern
- (Raw.Marker candidate)
- fixity <-
- entries
- , candidate == marker
- ] of
- [Interface.Fixity actualAssociativity actualLevel] -> do
- assertEqual
- (Text.unpack marker <> " associativity")
- associativity
- actualAssociativity
- assertEqual
- (Text.unpack marker <> " level")
- level
- (Interface.mixfixLevelValue actualLevel)
- actual ->
- assertFailure
- ("expected one fixity for "
- <> Text.unpack marker
- <> ", got "
- <> show actual)
-
-assertAxiomLeftShape
- :: String
- -> String
- -> Raw.Block
- -> Assertion
-assertAxiomLeftShape description expected block =
- case block of
- Raw.BlockAxiom
- _location
- _title
- _marker
- (Raw.Axiom
- _assumptions
- (Raw.StmtFormula
- (Raw.FormulaChain
- (Raw.ChainBase
- (expression :| [])
- _sign
- _relation
- _right)))) ->
- assertEqual
- description
- expected
- (expressionShape expression)
- _ ->
- assertFailure
- ("expected an axiom with one left expression, got "
- <> show block)
-
-expressionShape :: Raw.Expr -> String
-expressionShape = \case
- Raw.ExprVar (Raw.NamedVarAt _location name) ->
- Text.unpack name
- Raw.ExprOp
- _location
- symbol
- arguments ->
- let Raw.Marker marker =
- Raw.mixfixMarker symbol
- in
- Text.unpack marker
- <> "("
- <> List.intercalate ","
- (expressionShape <$> arguments)
- <> ")"
- expression ->
- show expression
-
-findParsedModule
- :: FilePath
- -> Parse.ParsedSourceWorkspace
- -> IO Parse.ParsedModule
-findParsedModule relative workspace =
- case List.find hasPath
- (Parse.parsedWorkspaceModules workspace) of
- Just parsed ->
- pure parsed
- Nothing ->
- assertFailure
- ("could not find parsed module " <> relative)
- where
- hasPath parsed =
- safeRelativePathFilePath
- (resolvedSourceRelativePath
- (Parse.parsedModuleResolved parsed))
- == relative
-
-writeAdjectiveDefinition :: FilePath -> String -> IO ()
-writeAdjectiveDefinition path marker =
- writeFile path (adjectiveDefinition marker)
-
-adjectiveDefinition :: String -> String
-adjectiveDefinition marker =
- unlines
- [ "\\begin{definition}\\label{" <> marker <> "}"
- , " $x$ is special iff $x = x$."
- , "\\end{definition}"
- ]
-
-writeNounDefinition :: FilePath -> String -> IO ()
-writeNounDefinition path marker =
- writeFile path
- (unlines
- [ "\\begin{definition}\\label{" <> marker <> "}"
- , " $x$ is a special iff $x = x$."
- , "\\end{definition}"
- ])
-
-writeBuiltinZeroDefinition :: FilePath -> String -> IO ()
-writeBuiltinZeroDefinition path marker =
- writeFile path (builtinZeroDefinition marker)
-
-builtinZeroDefinition :: String -> String
-builtinZeroDefinition marker =
- unlines
- [ "\\begin{abbreviation}\\label{" <> marker <> "}"
- , " $\\zero = \\emptyset$."
- , "\\end{abbreviation}"
- ]
-
-writeBuiltinCongDefinition :: FilePath -> IO ()
-writeBuiltinCongDefinition path =
- writeFile path
- (unlines
- [ "\\begin{definition}\\label{source_cong}"
- , " $\\Cong{x}{y}{z}{w}$ iff $x = x$."
- , "\\end{definition}"
- ])
-
-writeTheory :: FilePath -> [FilePath] -> String -> IO ()
-writeTheory path imports label =
- writeFile path
- (unlines
- (["\\import{" <> imported <> "}" | imported <- imports]
- <> [theoryBlock label]))
-
-theoryBlock :: String -> String
-theoryBlock label =
- unlines
- [ "\\begin{axiom}\\label{" <> label <> "}"
- , " $x = x$."
- , "\\end{axiom}"
- ]
-
-oneMount :: Text -> FilePath -> IO SourceMounts
-oneMount ident root =
- expectRight =<< prepareSourceMounts [(sourceMountId ident, root)]
-
-withTemporaryDirectory :: String -> (FilePath -> IO a) -> IO a
-withTemporaryDirectory template =
- bracket create Directory.removePathForcibly
- where
- create = do
- systemTemp <- Directory.getTemporaryDirectory
- (path, handle) <- openTempFile systemTemp template
- hClose handle
- Directory.removeFile path
- Directory.createDirectory path
- pure path
-
-assertRight :: (Show e, HasCallStack) => Either e a -> Assertion
-assertRight = void . expectRight
-
-expectRight :: (Show e, HasCallStack) => Either e a -> IO a
-expectRight = \case
- Left err ->
- assertFailure ("expected Right, got Left " <> show err)
- Right value ->
- pure value
-
-expectJust :: HasCallStack => String -> Maybe a -> IO a
-expectJust description = \case
- Nothing ->
- assertFailure ("expected " <> description)
- Just value ->
- pure value
-
-expectLexiconCollision
- :: Either Parse.ParseWorkspaceError a
- -> IO Parse.LexiconCollision
-expectLexiconCollision = \case
- Left (Parse.SourceLexiconCollision collision) ->
- pure collision
- Left err ->
- assertFailure
- ("expected SourceLexiconCollision, got " <> show err)
- Right _value ->
- assertFailure "expected SourceLexiconCollision, got Right"
-
-expectTwoCollisionLocations
- :: Parse.LexiconCollision
- -> IO (Location, Location)
-expectTwoCollisionLocations collision =
- case Parse.lexiconCollisionDeclarations collision of
- firstLocation : secondLocation : _ ->
- pure (firstLocation, secondLocation)
- locations ->
- assertFailure
- ("expected two source collision locations, got "
- <> show locations)
-
-assertLocation :: String -> FilePath -> Int -> Location -> Assertion
-assertLocation description expectedFile expectedLine location = do
- assertEqual (description <> " file")
- expectedFile
- (locFile location)
- assertEqual (description <> " line")
- expectedLine
- (locLine location)
- assertEqual (description <> " column")
- 1
- (locColumn location)
-
-substringIndex :: String -> String -> Int
-substringIndex needle haystack =
- fromMaybe maxBound
- (List.findIndex
- (List.isPrefixOf needle)
- (List.tails haystack))
-
-assertLeft :: (Eq e, Eq a, Show e, Show a, HasCallStack) => e -> Either e a -> Assertion
-assertLeft expected actual =
- assertEqual "expected Left value" (Left expected) actual
diff --git a/source/Test/Unit/Store.hs b/source/Test/Unit/Store.hs
deleted file mode 100644
index fb207d1..0000000
--- a/source/Test/Unit/Store.hs
+++ /dev/null
@@ -1,1675 +0,0 @@
-{-# LANGUAGE NoImplicitPrelude #-}
-
-module Test.Unit.Store (unitTests) where
-
-import Base
-import Checking.Authority qualified as Authority
-import Checking.Core qualified as Core
-import Checking.Declaration qualified as Declaration
-import Checking.Foundation qualified as Foundation
-import Checking.Identity qualified as Identity
-import Checking.Module qualified as Typed
-import Checking.Semantic qualified as Semantic
-import Felix.Cache.Codec qualified as Cache
-import Felix.Math.Codec
-import Felix.Module
-import Felix.Parsed.Identity qualified as Parsed
-import Felix.Parsed.Payload qualified as ParsedPayload
-import Felix.Source.Content qualified as Content
-import Felix.Source
-import Felix.Store qualified as Store
-import Felix.Provers qualified as Provers
-import Syntax.Interface qualified as Syntax
-
-import Control.Concurrent (threadDelay)
-import Control.Exception qualified as Exception
-import Data.ByteString qualified as ByteString
-import Data.ByteString.Char8 qualified as ByteString.Char8
-import Data.IORef qualified as IORef
-import Database.SQLite.Simple qualified as SQLite
-import Database.SQLite.Simple.Types (Only(..))
-import System.Directory qualified as Directory
-import System.Environment qualified as Environment
-import System.FilePath.Posix qualified as Posix
-import System.IO.Temp qualified as Temp
-import Test.Tasty
-import Test.Tasty.HUnit
-import UnliftIO.Async (concurrently)
-
-
-unitTests :: TestTree
-unitTests =
- testGroup "SQLite store"
- [ testCase "initializes and reopens the current schema"
- initializesAndReopensCurrentSchema
- , testCase "serializes invocation-local coordinator access"
- serializesCoordinatorAccess
- , testCase "rejects incompatibility without configuring the store"
- rejectsIncompatibilityWithoutConfiguration
- , testCase "rejects malformed compatibility metadata"
- rejectsMalformedCompatibilityMetadata
- , testCase "rejects a compatible incomplete schema"
- rejectsCompatibleIncompleteSchema
- , testCase "round-trips exact parsed artifacts"
- roundTripsExactParsedArtifacts
- , testCase "rejects malformed parsed payloads"
- rejectsMalformedParsedPayloads
- , testCase "rejects disagreeing parsed artifact identities"
- rejectsDisagreeingParsedArtifactIdentities
- , testCase "rejects malformed typed validation rows"
- rejectsMalformedTypedValidationRows
- , testCase "publishes a completed prefix before readiness"
- publishesCompletedPrefixBeforeReadiness
- , testCase "installs a sealed producer for a cached importer"
- installsSealedProducerForCachedImporter
- , testCase "validates exact cached installation inputs"
- validatesExactCachedInstallationInputs
- , testCase "rejects invalid cached root authority and closure"
- rejectsInvalidCachedRootAuthorityAndClosure
- , testCase "rejects disagreeing module artifact columns"
- rejectsDisagreeingModuleArtifactColumns
- , testCase "validates shared closures once per invocation"
- validatesSharedClosuresOncePerInvocation
- , testCase "rolls back a failed readiness transaction"
- rollsBackFailedReadiness
- , testCase "rolls back an unequal duplicate batch"
- rollsBackUnequalDuplicateBatch
- , testCase "rejects malformed canonical payloads"
- rejectsMalformedCanonicalPayloads
- , testCase "plans default and explicit persistent stores"
- plansPersistentStores
- , testCase "cleans fresh stores on return and exceptions"
- cleansFreshStores
- , testCase "does not fall back after fatal startup"
- doesNotFallBackAfterFatalStartup
- ]
-
-serializesCoordinatorAccess :: Assertion
-serializesCoordinatorAccess = do
- coordinator <- Store.newStoreCoordinator
- active <- IORef.newIORef (0 :: Int)
- maximumActive <- IORef.newIORef (0 :: Int)
- let operation =
- Store.withStoreCoordinator coordinator
- (Exception.bracket_
- (IORef.atomicModifyIORef' active
- (\current ->
- let next = current + 1
- in (next, ())))
- (IORef.atomicModifyIORef' active
- (\current -> (current - 1, ())))
- (do
- current <- IORef.readIORef active
- IORef.atomicModifyIORef' maximumActive
- (\observed -> (max current observed, ()))
- threadDelay 50000))
- void (concurrently operation operation)
- IORef.readIORef maximumActive >>= assertEqual "maximum owner count" 1
-
-roundTripsExactParsedArtifacts :: Assertion
-roundTripsExactParsedArtifacts =
- withStoreFixture "felix-store-parsed" \path theory _fixture -> do
- (_startup, store) <- expectOpen path theory
- (key, artifact, unequal) <- makeParsedArtifacts
- assertEqual "initial exact lookup misses" (Right Nothing)
- =<< Store.loadParsedArtifact store key
- assertEqual "published parsed artifact"
- (Right artifact)
- =<< Store.writeParsedArtifact store key artifact
- assertEqual "exact parsed round trip"
- (Right (Just artifact))
- =<< Store.loadParsedArtifact store key
- assertEqual "equal publication is idempotent"
- (Right artifact)
- =<< Store.writeParsedArtifact store key artifact
- Store.writeParsedArtifact store key unequal >>= \case
- Left Store.StoreRowPayloadMismatch{} ->
- pure ()
- other ->
- assertFailure
- ("unexpected unequal parsed publication: " <> show other)
- Store.closeStore store
-
-rejectsMalformedParsedPayloads :: Assertion
-rejectsMalformedParsedPayloads = do
- check "malformed" (ByteString.singleton 0xff)
- check "noncanonical" . (<> ByteString.singleton 0x00)
- =<< parsedPayloadBytes
- where
- check label corrupted =
- withStoreFixture ("felix-store-parsed-" <> label)
- \path theory _fixture -> do
- (_startup, store) <- expectOpen path theory
- (key, artifact, _unequal) <- makeParsedArtifacts
- _ <- expectRightIO
- (Store.writeParsedArtifact store key artifact)
- Store.closeStore store
- updateParsedPayload path key corrupted
- (_reopened, current) <- expectOpen path theory
- Store.loadParsedArtifact current key >>= \case
- Left Store.StoreRowDecodeFailure{} ->
- pure ()
- other ->
- assertFailure
- ("unexpected " <> label
- <> " parsed row result: " <> show other)
- Store.closeStore current
-
- parsedPayloadBytes = do
- (_key, artifact, _unequal) <- makeParsedArtifacts
- pure
- (ParsedPayload.canonicalParsedPayloadBytes
- (ParsedPayload.parsedArtifactPayload artifact))
-
-rejectsDisagreeingParsedArtifactIdentities :: Assertion
-rejectsDisagreeingParsedArtifactIdentities =
- withStoreFixture "felix-store-parsed-id" \path theory _fixture -> do
- (_startup, store) <- expectOpen path theory
- (key, artifact, _unequal) <- makeParsedArtifacts
- _ <- expectRightIO (Store.writeParsedArtifact store key artifact)
- Store.closeStore store
- connection <- SQLite.open path
- SQLite.execute connection
- "UPDATE parsed_artifacts SET parsed_module_id = ? \
- \WHERE parsed_module_key = ?"
- ( ByteString.replicate 32 0
- , Cache.cacheDigestBytes (Parsed.parsedModuleKeyDigest key)
- )
- SQLite.close connection
- (_reopened, current) <- expectOpen path theory
- Store.loadParsedArtifact current key >>= \case
- Left Store.StoreParsedArtifactIdMismatch ->
- pure ()
- other ->
- assertFailure
- ("unexpected parsed identity result: " <> show other)
- Store.closeStore current
-
-makeParsedArtifacts
- :: IO
- ( Parsed.ParsedModuleKey
- , ParsedPayload.ParsedArtifact
- , ParsedPayload.ParsedArtifact
- )
-makeParsedArtifacts = do
- key <- expectRight
- (Parsed.parsedModuleKey
- (Content.sourceContentIdBytes "parsed-source")
- Syntax.baseSyntaxInterfaceId
- [])
- emptyDelta <- expectRight (Syntax.canonicalSyntaxDelta [])
- emptySyntax <- expectRight (Syntax.moduleSyntaxInterface [] emptyDelta)
- otherDelta <- expectRight
- (Syntax.canonicalSyntaxDelta
- [Syntax.CanonicalStructureOperation "other"])
- otherSyntax <- expectRight
- (Syntax.moduleSyntaxInterface [] otherDelta)
- let payload syntax =
- ParsedPayload.canonicalParsedPayload
- [] [] [] (Syntax.moduleSyntaxAssertedId syntax)
- pure
- ( key
- , ParsedPayload.parsedArtifact key (payload emptySyntax)
- , ParsedPayload.parsedArtifact key (payload otherSyntax)
- )
-
-updateParsedPayload
- :: FilePath
- -> Parsed.ParsedModuleKey
- -> ByteString.ByteString
- -> IO ()
-updateParsedPayload path key payload = do
- connection <- SQLite.open path
- SQLite.execute connection
- "UPDATE parsed_artifacts SET payload = ? \
- \WHERE parsed_module_key = ?"
- ( payload
- , Cache.cacheDigestBytes (Parsed.parsedModuleKeyDigest key)
- )
- SQLite.close connection
-
-rejectsMalformedTypedValidationRows :: Assertion
-rejectsMalformedTypedValidationRows =
- withStoreFixture "felix-store-malformed-typed" \path theory fixture -> do
- (_startup, store) <- expectOpen path theory
- (_owner, prefix, _syntax, _semantic, _key, _artifact, _proposition) <-
- makeCommittedModule theory fixture
- batch <- case Declaration.pendingModulePrefixBatches prefix of
- [one] -> pure one
- batches ->
- assertFailure
- ("unexpected prefix batch count: " <> show (length batches))
- >> fail "unreachable"
- proof <- case Declaration.committedBatchProofValidations batch of
- [one] -> pure one
- proofs ->
- assertFailure
- ("unexpected proof validation count: " <> show (length proofs))
- >> fail "unreachable"
- let key = Semantic.proofValidationRecordKey proof
- certificate = Semantic.proofValidationRecordCertificate proof
- theorem = Identity.theoremId
- (Authority.factAuthorityTheorem
- (Authority.validationTarget certificate))
- wrongKey = Semantic.proofValidationKey
- theorem
- (Semantic.proofSyntaxId "other-row")
- (Declaration.committedBatchPreviousPrefix batch)
- wrongProof =
- Semantic.proofValidationRecord wrongKey certificate
- expectRightIO (Store.writePendingModulePrefix store prefix)
- Store.closeStore store
- connection <- SQLite.open path
- SQLite.execute connection
- "UPDATE proof_validations SET payload = ? \
- \WHERE validation_key = ?"
- ( Cache.encodeCache
- (Semantic.putProofValidationRecordCache wrongProof)
- , Cache.cacheDigestBytes
- (Semantic.proofValidationKeyDigest key)
- )
- SQLite.close connection
- (_reopened, current) <- expectOpen path theory
- Store.loadProofValidation current key >>= \case
- Left Store.StoreValidationRecordKeyMismatch{} -> pure ()
- Left other ->
- assertFailure
- ("unexpected typed key mismatch: " <> show other)
- Right _ ->
- assertFailure "typed key mismatch was accepted"
- Store.closeStore current
- connection' <- SQLite.open path
- SQLite.execute connection'
- "UPDATE proof_validations SET payload = ? \
- \WHERE validation_key = ?"
- ( ByteString.singleton 0xff
- , Cache.cacheDigestBytes
- (Semantic.proofValidationKeyDigest key)
- )
- SQLite.close connection'
- (_reopenedMalformed, malformed) <- expectOpen path theory
- Store.loadProofValidation malformed key >>= \case
- Left Store.StoreRowDecodeFailure{} -> pure ()
- Left other ->
- assertFailure
- ("unexpected malformed typed row: " <> show other)
- Right _ ->
- assertFailure "malformed typed row was accepted"
- Store.closeStore malformed
-
-publishesCompletedPrefixBeforeReadiness :: Assertion
-publishesCompletedPrefixBeforeReadiness =
- withStoreFixture "felix-store-prefix" \path theory fixture -> do
- (_startup, store) <- expectOpen path theory
- (_owner, prefix, syntax, semantic, artifactKey, artifact, proposition) <-
- makeCommittedModule theory fixture
- expectRightIO (Store.writePendingModulePrefix store prefix)
- connection <- SQLite.open path
- [Only propositionRows] <- SQLite.query connection
- "SELECT COUNT(*) FROM canonical_propositions \
- \WHERE proposition_id = ?"
- (Only
- (Cache.encodeCache
- (Identity.putPropositionIdCache
- (Identity.checkedPropositionId proposition))))
- :: IO [Only Int]
- [Only artifactRowsBefore] <- SQLite.query_ connection
- "SELECT COUNT(*) FROM module_artifacts"
- :: IO [Only Int]
- SQLite.close connection
- assertEqual "completed prefix proposition is visible" 1 propositionRows
- assertEqual "prefix publication does not publish readiness"
- 0 artifactRowsBefore
- expectRightIO
- (Store.writeSealedModule
- store
- prefix
- [syntax]
- [semantic]
- artifact)
- memo <- Store.newStoreMemo store
- installation <- expectRightIO
- (Store.loadCachedModuleInstallation
- memo
- store
- artifactKey
- (Syntax.moduleSyntaxAssertedId syntax))
- case installation of
- Just loaded -> do
- assertEqual "validated semantic interface" semantic
- (Store.cachedInstallationSemantic loaded)
- assertEqual "validated imported proposition count" 1
- (length (Store.cachedInstallationPropositions loaded))
- Nothing ->
- assertFailure "validated module installation was absent"
- Store.closeStore store
-
-installsSealedProducerForCachedImporter :: Assertion
-installsSealedProducerForCachedImporter =
- withStoreFixture "felix-store-cached-import" \path theory fixture -> do
- (_startup, store) <- expectOpen path theory
- foundation <- expectRight Foundation.checkedFoundation
- (_owner, prefix, syntax, semantic, artifactKey, artifact, proposition) <-
- makeCommittedModule theory fixture
- expectRightIO
- (Store.writeSealedModule
- store
- prefix
- [syntax]
- [semantic]
- artifact)
- memo <- Store.newStoreMemo store
- installation <-
- expectRightIO
- (Store.loadCachedModuleInstallation
- memo
- store
- artifactKey
- (Syntax.moduleSyntaxAssertedId syntax))
- >>= \case
- Nothing ->
- assertFailure "sealed producer was not loadable"
- >> fail "unreachable"
- Just loaded ->
- pure loaded
- cached <- expectRight
- (Typed.cachedSealedTypedModule
- foundation
- []
- installation)
- let loadedSemantic = Store.cachedInstallationSemantic installation
- fingerprint <-
- case concatMap
- Semantic.declarationDeltaFacts
- (Semantic.semanticInterfaceDeclarations loadedSemantic) of
- [occurrence] ->
- pure (Semantic.semanticFactFingerprint occurrence)
- occurrences ->
- assertFailure
- ("unexpected cached producer facts: "
- <> show (length occurrences))
- >> fail "unreachable"
- namespaceDigest <- expectRight
- (hashCanonicalFields
- "store-cached-import-consumer"
- ["consumer"])
- relative <- expectRight (safeRelativePath "consumer.tex")
- let consumerOwner =
- moduleNameFromParts
- (sourceNamespaceIdFromDigest namespaceDigest)
- relative
- resolver = Declaration.vampireResolver \_ ->
- pure
- (Left
- (Provers.ProverLaunchFailed
- "unused"
- "cached importer does not run Vampire"))
- result <-
- (Declaration.runModuleDriver
- foundation
- consumerOwner
- [Semantic.semanticInterfaceAssertedId loadedSemantic]
- resolver
- Declaration.FreshValidation
- do
- Declaration.importSealedModuleDriver
- (Typed.sealedTypedModuleEvidence cached)
- (_value, batch) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "cached-import-consumer") do
- candidate <- Declaration.reserveCandidate
- (Declaration.candidateSpec
- proposition
- Semantic.SearchIneligible
- [])
- Declaration.authorizeOmittedCandidate candidate do
- _ <- Declaration.useAuthorizedFact fingerprint
- Declaration.recordOmittedUse
- pure batch
- :: IO
- (Either
- Declaration.DriverOpenError
- (Declaration.DriverResult Text
- Declaration.CommittedDeclarationBatch)))
- case result of
- Left failure ->
- assertFailure ("cached importer could not open: " <> show failure)
- Right (Declaration.DriverSucceeded _ _ _ _closure) ->
- pure ()
- Right (Declaration.DriverFailed failure _prefix) ->
- assertFailure ("cached importer failed: " <> show failure)
- Right (Declaration.DriverSealFailed failure _prefix) ->
- assertFailure ("cached importer did not seal: " <> show failure)
- Store.closeStore store
-
-validatesExactCachedInstallationInputs :: Assertion
-validatesExactCachedInstallationInputs =
- withStoreFixture "felix-store-exact-install" \path theory fixture -> do
- (_startup, store) <- expectOpen path theory
- (owner, prefix, syntax, semantic, artifactKey, artifact, proposition) <-
- makeCommittedModule theory fixture
- _ <- expectRightIO
- (Store.writeSealedModule
- store prefix [syntax] [semantic] artifact)
- otherDelta <- expectRight
- (Syntax.canonicalSyntaxDelta
- [Syntax.CanonicalStructureOperation "other-syntax"])
- otherSyntax <- expectRight
- (Syntax.moduleSyntaxInterface [] otherDelta)
- wrongSyntaxMemo <- Store.newStoreMemo store
- Store.loadCachedModuleInstallation
- wrongSyntaxMemo
- store
- artifactKey
- (Syntax.moduleSyntaxAssertedId otherSyntax)
- >>= \case
- Left Store.StoreModuleArtifactSyntaxMismatch{} -> pure ()
- _ ->
- assertFailure "unexpected syntax-input result"
-
- parent <- expectRight
- (Semantic.semanticInterface preludeModuleName [] [])
- mismatched <- expectRight
- (Semantic.semanticInterface
- owner
- [Semantic.semanticInterfaceAssertedId parent]
- (Semantic.semanticInterfaceDeclarations semantic))
- mismatchKey <- makeArtifactKey owner theory "direct-mismatch"
- let mismatchArtifact =
- Semantic.moduleArtifactResult
- mismatchKey
- (Syntax.moduleSyntaxAssertedId syntax)
- (Semantic.semanticInterfaceAssertedId mismatched)
- writeRawModuleRows
- path
- [fixtureFirstObject fixture]
- [proposition]
- syntax
- [parent, mismatched]
- mismatchArtifact
- directMemo <- Store.newStoreMemo store
- Store.loadCachedModuleInstallation
- directMemo
- store
- mismatchKey
- (Syntax.moduleSyntaxAssertedId syntax)
- >>= \case
- Left Store.StoreModuleArtifactDirectMismatch{} -> pure ()
- _ ->
- assertFailure "unexpected direct-input result"
- Store.closeStore store
-
-rejectsInvalidCachedRootAuthorityAndClosure :: Assertion
-rejectsInvalidCachedRootAuthorityAndClosure =
- withStoreFixture "felix-store-invalid-install" \path theory fixture -> do
- (_startup, store) <- expectOpen path theory
- (owner, _prefix, syntax, semantic, _artifactKey, _artifact, proposition) <-
- makeCommittedModule theory fixture
- otherTheory <- expectRight
- (Cache.decodeCache
- Identity.getTheoryIdCache
- (ByteString.replicate 32 0x5a))
- original <- case Semantic.semanticInterfaceDeclarations semantic of
- [delta] -> pure delta
- deltas ->
- assertFailure
- ("unexpected declaration count: " <> show (length deltas))
- >> fail "unreachable"
- occurrence <- case Semantic.declarationDeltaFacts original of
- [fact] -> pure fact
- facts ->
- assertFailure
- ("unexpected fact count: " <> show (length facts))
- >> fail "unreachable"
- let badAuthority =
- Authority.factAuthority
- (Identity.theoremRef
- otherTheory
- (Semantic.semanticFactProposition occurrence))
- (Authority.factAuthoritySafety
- (Semantic.semanticFactAuthority occurrence))
- badOccurrence =
- Semantic.semanticFactOccurrence
- (Semantic.semanticFactSlot occurrence)
- badAuthority
- (Semantic.semanticFactSearchEligibility occurrence)
- badDelta <- expectRight
- (Semantic.declarationInterfaceDelta
- (Semantic.declarationDeltaSlot original)
- [badOccurrence]
- (Semantic.declarationDeltaAliases original)
- (Semantic.declarationDeltaObjects original)
- (Semantic.declarationDeltaPropositions original)
- (Semantic.declarationDeltaEnvironment original))
- badSemantic <- expectRight
- (Semantic.semanticInterface owner [] [badDelta])
- badKey <- makeArtifactKey owner theory "bad-authority"
- let badArtifact =
- Semantic.moduleArtifactResult
- badKey
- (Syntax.moduleSyntaxAssertedId syntax)
- (Semantic.semanticInterfaceAssertedId badSemantic)
- writeRawModuleRows
- path
- [fixtureFirstObject fixture]
- [proposition]
- syntax
- [badSemantic]
- badArtifact
- badMemo <- Store.newStoreMemo store
- Store.loadCachedModuleInstallation
- badMemo store badKey (Syntax.moduleSyntaxAssertedId syntax)
- >>= \case
- Left Store.StoreImportedOccurrenceValidationFailure{} -> pure ()
- _ ->
- assertFailure "unexpected root-authority result"
-
- childKey <- makeArtifactKey owner theory "missing-late-child"
- let childArtifact =
- Semantic.moduleArtifactResult
- childKey
- (Syntax.moduleSyntaxAssertedId syntax)
- (Semantic.semanticInterfaceAssertedId semantic)
- writeRawModuleRows
- path
- [fixtureFirstObject fixture]
- [proposition]
- syntax
- [semantic]
- childArtifact
- connection <- SQLite.open path
- SQLite.execute connection
- "DELETE FROM canonical_objects WHERE object_id = ?"
- (Only
- (Cache.encodeCache
- (Identity.putObjectIdCache
- (Identity.assertedObjectId
- (fixtureFirstObject fixture)))))
- SQLite.close connection
- childMemo <- Store.newStoreMemo store
- Store.loadCachedModuleInstallation
- childMemo store childKey (Syntax.moduleSyntaxAssertedId syntax)
- >>= \case
- Left Store.StoreAssertedChildMissing{} -> pure ()
- _ ->
- assertFailure "unexpected missing-child result"
- Store.closeStore store
-
-rejectsDisagreeingModuleArtifactColumns :: Assertion
-rejectsDisagreeingModuleArtifactColumns =
- withStoreFixture "felix-store-artifact-columns" \path theory fixture -> do
- (_startup, store) <- expectOpen path theory
- (_owner, prefix, syntax, semantic, key, artifact, _proposition) <-
- makeCommittedModule theory fixture
- _ <- expectRightIO
- (Store.writeSealedModule
- store prefix [syntax] [semantic] artifact)
- connection <- SQLite.open path
- SQLite.execute_ connection "PRAGMA foreign_keys = OFF"
- SQLite.execute connection
- "UPDATE module_artifacts SET syntax_interface_id = ? \
- \WHERE module_artifact_id = ?"
- ( ByteString.replicate 32 0x3c
- , Cache.cacheDigestBytes
- (Semantic.moduleArtifactIdDigest
- (Semantic.moduleArtifactResultId artifact))
- )
- SQLite.close connection
- memo <- Store.newStoreMemo store
- Store.loadCachedModuleInstallation
- memo
- store
- key
- (Syntax.moduleSyntaxAssertedId syntax)
- >>= \case
- Left Store.StoreModuleArtifactColumnsMismatch -> pure ()
- Left other ->
- assertFailure
- ("unexpected artifact-column load: " <> show other)
- Right _ ->
- assertFailure "disagreeing artifact columns were accepted"
- Store.writeSealedModule
- store prefix [syntax] [semantic] artifact >>= \case
- Left Store.StoreRowPayloadMismatch{} -> pure ()
- other ->
- assertFailure
- ("unexpected artifact-column rewrite: " <> show other)
- Store.closeStore store
-
-validatesSharedClosuresOncePerInvocation :: Assertion
-validatesSharedClosuresOncePerInvocation =
- withStoreFixture "felix-store-linear-closure" \path theory fixture -> do
- (_startup, store) <- expectOpen path theory
- let baseObject = fixtureFirstObject fixture
- first = transparentSetObject theory baseObject
- second = transparentSetObject theory first
- third = transparentSetObject theory second
- objects = [baseObject, first, second, third]
- closure <- expectRight
- (Identity.validateObjectClosure theory objects)
- proposition <- expectRight
- (Identity.validatePropositionContent
- closure
- (Core.CEq
- Core.TySet
- (Core.CGlobal (Identity.assertedObjectId third))
- (Core.CGlobal (Identity.assertedObjectId third))))
- baseOwner <- testModuleName "linear-base.tex"
- leftOwner <- testModuleName "linear-left.tex"
- rightOwner <- testModuleName "linear-right.tex"
- rootOwner <- testModuleName "linear-root.tex"
- let theorem = Identity.theoremRef
- theory
- (Identity.checkedPropositionId proposition)
- occurrence = Semantic.semanticFactOccurrence
- (Semantic.factSlot baseOwner (localFactOrdinal 0))
- (Authority.factAuthority
- theorem Authority.cleanAuthoritySafety)
- Semantic.SearchEligible
- baseDelta <- expectRight
- (Semantic.declarationInterfaceDelta
- (Semantic.declarationSlot
- baseOwner
- (localDeclarationOrdinal 0))
- [occurrence]
- []
- (Identity.assertedObjectId <$> objects)
- [Identity.checkedPropositionId proposition]
- Semantic.emptySemanticEnvironmentDelta)
- baseSemantic <- expectRight
- (Semantic.semanticInterface baseOwner [] [baseDelta])
- leftSemantic <- expectRight
- (Semantic.semanticInterface
- leftOwner
- [Semantic.semanticInterfaceAssertedId baseSemantic]
- [])
- rightSemantic <- expectRight
- (Semantic.semanticInterface
- rightOwner
- [Semantic.semanticInterfaceAssertedId baseSemantic]
- [])
- rootSemantic <- expectRight
- (Semantic.semanticInterface
- rootOwner
- [ Semantic.semanticInterfaceAssertedId leftSemantic
- , Semantic.semanticInterfaceAssertedId rightSemantic
- ]
- [])
-
- emptyDelta <- expectRight (Syntax.canonicalSyntaxDelta [])
- leftDelta <- expectRight
- (Syntax.canonicalSyntaxDelta
- [Syntax.CanonicalStructureOperation "linear-left"])
- rightDelta <- expectRight
- (Syntax.canonicalSyntaxDelta
- [Syntax.CanonicalStructureOperation "linear-right"])
- baseSyntax <- expectRight
- (Syntax.moduleSyntaxInterface [] emptyDelta)
- leftSyntax <- expectRight
- (Syntax.moduleSyntaxInterface
- [Syntax.moduleSyntaxAssertedId baseSyntax]
- leftDelta)
- rightSyntax <- expectRight
- (Syntax.moduleSyntaxInterface
- [Syntax.moduleSyntaxAssertedId baseSyntax]
- rightDelta)
- rootSyntax <- expectRight
- (Syntax.moduleSyntaxInterface
- [ Syntax.moduleSyntaxAssertedId leftSyntax
- , Syntax.moduleSyntaxAssertedId rightSyntax
- ]
- emptyDelta)
-
- rootKey <- makeArtifactKeyWithDirect
- rootOwner
- theory
- [ Semantic.semanticInterfaceAssertedId leftSemantic
- , Semantic.semanticInterfaceAssertedId rightSemantic
- ]
- "linear-root"
- leftKey <- makeArtifactKeyWithDirect
- leftOwner
- theory
- [Semantic.semanticInterfaceAssertedId baseSemantic]
- "linear-left"
- let rootArtifact = Semantic.moduleArtifactResult
- rootKey
- (Syntax.moduleSyntaxAssertedId rootSyntax)
- (Semantic.semanticInterfaceAssertedId rootSemantic)
- leftArtifact = Semantic.moduleArtifactResult
- leftKey
- (Syntax.moduleSyntaxAssertedId leftSyntax)
- (Semantic.semanticInterfaceAssertedId leftSemantic)
- connection <- SQLite.open path
- SQLite.withTransaction connection do
- traverse_ (insertRawObject connection) objects
- insertRawProposition connection proposition
- traverse_
- (insertRawSyntaxInterface connection)
- [baseSyntax, leftSyntax, rightSyntax, rootSyntax]
- traverse_
- (insertRawSemanticInterface connection)
- [baseSemantic, leftSemantic, rightSemantic, rootSemantic]
- insertRawModuleArtifact connection rootArtifact
- insertRawModuleArtifact connection leftArtifact
- SQLite.close connection
-
- memo <- Store.newStoreMemo store
- expectInstallation memo store rootKey rootSyntax
- expectInstallation memo store leftKey leftSyntax
- expectInstallation memo store rootKey rootSyntax
- visits <- Store.storeMemoVisits memo
- assertEqual "unique artifact rows" 2
- (Store.storeArtifactRowsDecoded visits)
- assertEqual "unique artifact validations" 2
- (Store.storeArtifactsValidated visits)
- assertEqual "syntax diamond rows" 4
- (Store.storeSyntaxRowsDecoded visits)
- assertEqual "syntax diamond validations" 4
- (Store.storeSyntaxRowsValidated visits)
- assertEqual "semantic diamond rows" 4
- (Store.storeSemanticRowsDecoded visits)
- assertEqual "semantic diamond validations" 4
- (Store.storeSemanticRowsValidated visits)
- assertEqual "transparent-chain rows" 4
- (Store.storeObjectRowsDecoded visits)
- assertEqual "transparent-chain validations" 4
- (Store.storeObjectRowsValidated visits)
- assertEqual "proposition rows" 1
- (Store.storePropositionRowsDecoded visits)
- assertEqual "proposition validations" 1
- (Store.storePropositionRowsValidated visits)
- Store.closeStore store
- where
- expectInstallation memo store key syntax =
- Store.loadCachedModuleInstallation
- memo store key (Syntax.moduleSyntaxAssertedId syntax)
- >>= \case
- Right (Just _installation) -> pure ()
- _ -> assertFailure "cached closure installation failed"
-
-transparentSetObject
- :: Identity.TheoryId
- -> Identity.AssertedObject
- -> Identity.AssertedObject
-transparentSetObject theory dependency =
- Identity.assertedObject identity content
- where
- content = Identity.TransparentObjectContent
- theory
- Core.TySet
- (Core.CGlobal (Identity.assertedObjectId dependency))
- identity = Identity.transparentObjectId
- theory
- Core.TySet
- (Core.CGlobal (Identity.assertedObjectId dependency))
-
-testModuleName :: FilePath -> IO ModuleName
-testModuleName path = do
- digest <- expectRight
- (hashCanonicalFields
- "store-linear-module"
- [ByteString.Char8.pack path])
- relative <- expectRight (safeRelativePath path)
- pure
- (moduleNameFromParts
- (sourceNamespaceIdFromDigest digest)
- relative)
-
-makeArtifactKey
- :: ModuleName
- -> Identity.TheoryId
- -> ByteString.ByteString
- -> IO Semantic.ModuleArtifactKey
-makeArtifactKey owner theory label = do
- makeArtifactKeyWithDirect owner theory [] label
-
-makeArtifactKeyWithDirect
- :: ModuleName
- -> Identity.TheoryId
- -> [Semantic.SemanticInterfaceId]
- -> ByteString.ByteString
- -> IO Semantic.ModuleArtifactKey
-makeArtifactKeyWithDirect owner theory direct label = do
- parsedKey <- expectRight
- (Parsed.parsedModuleKey
- (Content.sourceContentIdBytes label)
- Syntax.baseSyntaxInterfaceId
- [])
- expectRight
- (Semantic.moduleArtifactKey
- owner
- (Parsed.parsedModuleId parsedKey label)
- direct
- theory)
-
-writeRawModuleRows
- :: FilePath
- -> [Identity.AssertedObject]
- -> [Identity.CheckedPropositionContent]
- -> Syntax.ModuleSyntaxInterface
- -> [Semantic.SemanticInterface]
- -> Semantic.ModuleArtifactResult
- -> IO ()
-writeRawModuleRows path objects propositions syntax semantics artifact = do
- connection <- SQLite.open path
- SQLite.withTransaction connection do
- traverse_ (insertRawObject connection) objects
- traverse_ (insertRawProposition connection) propositions
- insertRawSyntaxInterface connection syntax
- traverse_ (insertRawSemanticInterface connection) semantics
- insertRawModuleArtifact connection artifact
- SQLite.close connection
-
-insertRawObject :: SQLite.Connection -> Identity.AssertedObject -> IO ()
-insertRawObject connection object =
- SQLite.execute connection
- "INSERT OR IGNORE INTO canonical_objects (object_id, payload) \
- \VALUES (?, ?)"
- ( Cache.encodeCache
- (Identity.putObjectIdCache
- (Identity.assertedObjectId object))
- , Cache.encodeCache
- (Identity.putObjectContentCache
- (Identity.assertedObjectContent object))
- )
-
-insertRawProposition
- :: SQLite.Connection
- -> Identity.CheckedPropositionContent
- -> IO ()
-insertRawProposition connection proposition =
- SQLite.execute connection
- "INSERT OR IGNORE INTO canonical_propositions \
- \(proposition_id, payload) VALUES (?, ?)"
- ( Cache.encodeCache
- (Identity.putPropositionIdCache
- (Identity.checkedPropositionId proposition))
- , Cache.encodeCache
- (Cache.putCanonicalTermCache
- Identity.putObjectIdCache
- (Core.frozenCoreTerm
- (Identity.checkedPropositionTerm proposition)))
- )
-
-insertRawSyntaxInterface
- :: SQLite.Connection
- -> Syntax.ModuleSyntaxInterface
- -> IO ()
-insertRawSyntaxInterface connection interface =
- SQLite.execute connection
- "INSERT OR IGNORE INTO syntax_interfaces \
- \(syntax_interface_id, payload) VALUES (?, ?)"
- ( Cache.cacheDigestBytes
- (Syntax.syntaxInterfaceIdDigest
- (Syntax.moduleSyntaxAssertedId interface))
- , Cache.encodeCache
- (Syntax.putModuleSyntaxInterfaceCache interface)
- )
-
-insertRawSemanticInterface
- :: SQLite.Connection
- -> Semantic.SemanticInterface
- -> IO ()
-insertRawSemanticInterface connection interface =
- SQLite.execute connection
- "INSERT OR IGNORE INTO semantic_interfaces \
- \(semantic_interface_id, payload) VALUES (?, ?)"
- ( Cache.cacheDigestBytes
- (Semantic.semanticInterfaceIdDigest
- (Semantic.semanticInterfaceAssertedId interface))
- , Cache.encodeCache
- (Semantic.putSemanticInterfaceCache interface)
- )
-
-insertRawModuleArtifact
- :: SQLite.Connection
- -> Semantic.ModuleArtifactResult
- -> IO ()
-insertRawModuleArtifact connection artifact =
- SQLite.execute connection
- "INSERT OR IGNORE INTO module_artifacts \
- \(module_artifact_id, syntax_interface_id, \
- \semantic_interface_id, payload) VALUES (?, ?, ?, ?)"
- ( Cache.cacheDigestBytes
- (Semantic.moduleArtifactIdDigest
- (Semantic.moduleArtifactResultId artifact))
- , Cache.cacheDigestBytes
- (Syntax.syntaxInterfaceIdDigest
- (Semantic.moduleArtifactResultSyntax artifact))
- , Cache.cacheDigestBytes
- (Semantic.semanticInterfaceIdDigest
- (Semantic.moduleArtifactResultSemantic artifact))
- , Cache.encodeCache
- (Semantic.putModuleArtifactResultCache artifact)
- )
-
-storedPropositionCount
- :: FilePath
- -> Identity.PropositionId
- -> IO Int
-storedPropositionCount path identity = do
- connection <- SQLite.open path
- [Only rowCount] <- SQLite.query connection
- "SELECT COUNT(*) FROM canonical_propositions \
- \WHERE proposition_id = ?"
- (Only
- (Cache.encodeCache
- (Identity.putPropositionIdCache identity)))
- SQLite.close connection
- pure rowCount
-
-storedObjectCount
- :: FilePath
- -> Identity.ObjectId
- -> IO Int
-storedObjectCount path identity = do
- connection <- SQLite.open path
- [Only rowCount] <- SQLite.query connection
- "SELECT COUNT(*) FROM canonical_objects WHERE object_id = ?"
- (Only
- (Cache.encodeCache
- (Identity.putObjectIdCache identity)))
- SQLite.close connection
- pure rowCount
-
-storedArtifactCount
- :: FilePath
- -> Semantic.ModuleArtifactId
- -> IO Int
-storedArtifactCount path identity = do
- connection <- SQLite.open path
- [Only rowCount] <- SQLite.query connection
- "SELECT COUNT(*) FROM module_artifacts \
- \WHERE module_artifact_id = ?"
- (Only
- (Cache.cacheDigestBytes
- (Semantic.moduleArtifactIdDigest identity)))
- SQLite.close connection
- pure rowCount
-
-rollsBackFailedReadiness :: Assertion
-rollsBackFailedReadiness =
- withStoreFixture "felix-store-readiness-rollback" \path theory fixture -> do
- (_startup, store) <- expectOpen path theory
- (owner, prefix, _syntax, semantic, _artifactKey, artifact, proposition) <-
- makeCommittedModule theory fixture
- missingDelta <- expectRight
- (Syntax.canonicalSyntaxDelta
- [Syntax.CanonicalStructureOperation "missing-child"])
- missingInterface <- expectRight
- (Syntax.moduleSyntaxInterface [] missingDelta)
- syntaxDelta <- expectRight
- (Syntax.canonicalSyntaxDelta [])
- brokenSyntax <- expectRight
- (Syntax.moduleSyntaxInterface
- [Syntax.moduleSyntaxAssertedId missingInterface]
- syntaxDelta)
- brokenParsedKey <- expectRight
- (Parsed.parsedModuleKey
- (Content.sourceContentIdBytes "rollback-source")
- Syntax.baseSyntaxInterfaceId
- [])
- brokenArtifactKey <- expectRight
- (Semantic.moduleArtifactKey
- owner
- (Parsed.parsedModuleId
- brokenParsedKey
- "rollback-parsed")
- []
- theory)
- let brokenArtifact =
- Semantic.moduleArtifactResult
- brokenArtifactKey
- (Syntax.moduleSyntaxAssertedId brokenSyntax)
- (Semantic.semanticInterfaceAssertedId semantic)
- result <- Store.writeSealedModule
- store
- prefix
- [brokenSyntax]
- [semantic]
- brokenArtifact
- case result of
- Left Store.StoreAssertedChildMissing{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected readiness failure: " <> show other)
- Right _ ->
- assertFailure "broken readiness transaction was accepted"
- assertEqual "failed readiness did not publish the prefix" 0
- =<< storedPropositionCount
- path
- (Identity.checkedPropositionId proposition)
- assertEqual "failed readiness leaves no module root" 0
- =<< storedArtifactCount
- path
- (Semantic.moduleArtifactResultId artifact)
- -- A later failed seal must not erase a prefix published by an
- -- earlier successful source prefix flush.
- expectRightIO (Store.writePendingModulePrefix store prefix)
- assertEqual "successful prefix is visible before retry" 1
- =<< storedPropositionCount
- path
- (Identity.checkedPropositionId proposition)
- retry <- Store.writeSealedModule
- store
- prefix
- [brokenSyntax]
- [semantic]
- brokenArtifact
- case retry of
- Left Store.StoreAssertedChildMissing{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected retry readiness failure: " <> show other)
- Right _ ->
- assertFailure "broken readiness retry was accepted"
- assertEqual "failed retry retains successful prefix" 1
- =<< storedPropositionCount
- path
- (Identity.checkedPropositionId proposition)
- assertEqual "failed retry still leaves no module root" 0
- =<< storedArtifactCount
- path
- (Semantic.moduleArtifactResultId artifact)
- Store.closeStore store
-makeCommittedModule
- :: Identity.TheoryId
- -> StoreFixture
- -> IO
- ( ModuleName
- , Declaration.PendingModulePrefix
- , Syntax.ModuleSyntaxInterface
- , Semantic.SemanticInterface
- , Semantic.ModuleArtifactKey
- , Semantic.ModuleArtifactResult
- , Identity.CheckedPropositionContent
- )
-makeCommittedModule theory fixture = do
- foundation <- expectRight Foundation.checkedFoundation
- namespaceDigest <- expectRight
- (hashCanonicalFields "store-module-test" ["prefix"])
- relative <- expectRight (safeRelativePath "module.tex")
- let owner =
- moduleNameFromParts
- (sourceNamespaceIdFromDigest namespaceDigest)
- relative
- proposition = fixtureProposition fixture
- resolver = Declaration.vampireResolver \_ ->
- pure
- (Left
- (Provers.ProverLaunchFailed
- "unused"
- "store fixture does not run Vampire"))
- driver <- Declaration.runModuleDriver
- foundation
- owner
- []
- resolver
- Declaration.FreshValidation
- do
- (_value, _batch) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "store-prefix") do
- Declaration.addDeclarationObject
- (fixtureFirstObject fixture)
- candidate <- Declaration.reserveCandidate
- (Declaration.candidateSpec
- proposition
- Semantic.SearchIneligible
- [])
- Declaration.authorizeOmittedCandidate candidate
- Declaration.recordOmittedUse
- pure ()
- (_value, prefix, semantic) <-
- case driver of
- Right (Declaration.DriverSucceeded value interface pending _closure) ->
- pure (value, pending, interface)
- Right (Declaration.DriverFailed failure _prefix) ->
- assertFailure
- ("unexpected declaration failure: "
- <> show
- (failure
- :: Declaration.DriverFailure
- Declaration.DeclarationError))
- >> fail "unreachable"
- Right (Declaration.DriverSealFailed failure _prefix) ->
- assertFailure ("unexpected seal failure: " <> show failure)
- >> fail "unreachable"
- Left failure ->
- assertFailure ("unexpected driver-open failure: " <> show failure)
- >> fail "unreachable"
- delta <- expectRight (Syntax.canonicalSyntaxDelta [])
- syntax <- expectRight (Syntax.moduleSyntaxInterface [] delta)
- parsedKey <- expectRight
- (Parsed.parsedModuleKey
- (Content.sourceContentIdBytes "store-module-source")
- Syntax.baseSyntaxInterfaceId
- [])
- artifactKey <- expectRight
- (Semantic.moduleArtifactKey
- owner
- (Parsed.parsedModuleId parsedKey "store-module-parsed")
- []
- theory)
- let artifact =
- Semantic.moduleArtifactResult
- artifactKey
- (Syntax.moduleSyntaxAssertedId syntax)
- (Semantic.semanticInterfaceAssertedId semantic)
- pure
- ( owner
- , prefix
- , syntax
- , semantic
- , artifactKey
- , artifact
- , proposition
- )
-
-makePendingPrefix
- :: StoreFixture
- -> [Identity.AssertedObject]
- -> IO Declaration.PendingModulePrefix
-makePendingPrefix fixture objects = do
- foundation <- expectRight Foundation.checkedFoundation
- owner <- testModuleName "rollback-prefix.tex"
- let proposition = fixtureProposition fixture
- resolver = Declaration.vampireResolver \_ ->
- pure
- (Left
- (Provers.ProverLaunchFailed
- "unused"
- "store fixture does not run Vampire"))
- driver <- Declaration.runModuleDriver
- foundation
- owner
- []
- resolver
- Declaration.FreshValidation
- do
- (_value, _batch) <- Declaration.commitProofDeclaration
- (Semantic.proofSyntaxId "store-rollback") do
- traverse_ Declaration.addDeclarationObject objects
- candidate <- Declaration.reserveCandidate
- (Declaration.candidateSpec
- proposition
- Semantic.SearchIneligible
- [])
- Declaration.authorizeOmittedCandidate candidate
- Declaration.recordOmittedUse
- pure ()
- case driver of
- Right (Declaration.DriverSucceeded _value _interface prefix _closure) ->
- pure prefix
- Right (Declaration.DriverFailed failure _prefix) ->
- assertFailure
- ("unexpected declaration failure: "
- <> show
- (failure
- :: Declaration.DriverFailure
- Declaration.DeclarationError))
- >> fail "unreachable"
- Right (Declaration.DriverSealFailed failure _prefix) ->
- assertFailure ("unexpected seal failure: " <> show failure)
- >> fail "unreachable"
- Left failure ->
- assertFailure ("unexpected driver-open failure: " <> show failure)
- >> fail "unreachable"
-
-initializesAndReopensCurrentSchema :: Assertion
-initializesAndReopensCurrentSchema =
- withStoreFixture "felix-store-startup" \path theory _fixture -> do
- (startup, store) <- expectOpen path theory
- assertEqual "new store status"
- Store.InitializedNewStore startup
- Store.closeStore store
-
- (reopened, current) <- expectOpen path theory
- assertEqual "current store status"
- Store.OpenedCurrentStore reopened
- Store.closeStore current
-
- connection <- SQLite.open path
- names <- SQLite.query_ connection
- "SELECT name FROM sqlite_master \
- \WHERE type = 'table' AND name NOT LIKE 'sqlite_%' \
- \ORDER BY name"
- :: IO [Only Text]
- journal <- SQLite.query_ connection
- "PRAGMA journal_mode"
- :: IO [Only Text]
- SQLite.close connection
- assertEqual "complete schema table count" 9 (length names)
- assertEqual "rollback journal persists"
- [Only "delete"] journal
-
-rejectsIncompatibilityWithoutConfiguration :: Assertion
-rejectsIncompatibilityWithoutConfiguration =
- withStoreFixture "felix-store-incompatible" \path theory _fixture -> do
- connection <- SQLite.open path
- _ <- SQLite.query_ connection
- "PRAGMA journal_mode = WAL"
- :: IO [Only Text]
- SQLite.execute_ connection
- "CREATE TABLE store_compatibility ( \
- \singleton INTEGER, cache_epoch INTEGER, theory_id BLOB )"
- SQLite.execute connection
- "INSERT INTO store_compatibility VALUES (1, ?, ?)"
- ( 999 :: Int
- , Cache.encodeCache (Identity.putTheoryIdCache theory)
- )
- SQLite.execute_ connection
- "CREATE TABLE untouched (value INTEGER)"
- SQLite.close connection
-
- result <- Store.openStore path theory
- case result of
- Left
- (Store.IncompatibleStore
- Store.StoreCompatibilityMismatch{}) ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected incompatibility result: " <> show other)
- Right (_startup, store) -> do
- Store.closeStore store
- assertFailure "incompatible store was accepted"
-
- inspected <- SQLite.open path
- names <- SQLite.query_ inspected
- "SELECT name FROM sqlite_master \
- \WHERE type = 'table' AND name NOT LIKE 'sqlite_%' \
- \ORDER BY name"
- :: IO [Only Text]
- journal <- SQLite.query_ inspected
- "PRAGMA journal_mode"
- :: IO [Only Text]
- SQLite.close inspected
- assertEqual "startup creates no schema"
- [Only "store_compatibility", Only "untouched"] names
- assertEqual "startup applies no journal configuration"
- [Only "wal"] journal
-
-rejectsMalformedCompatibilityMetadata :: Assertion
-rejectsMalformedCompatibilityMetadata =
- withStoreFixture "felix-store-malformed" \path theory _fixture -> do
- connection <- SQLite.open path
- SQLite.execute_ connection
- "CREATE TABLE store_compatibility ( \
- \singleton INTEGER, cache_epoch, theory_id )"
- SQLite.execute connection
- "INSERT INTO store_compatibility VALUES (1, ?, ?)"
- ( "not-an-epoch" :: Text
- , Cache.encodeCache (Identity.putTheoryIdCache theory)
- )
- SQLite.close connection
-
- result <- Store.openStore path theory
- case result of
- Left
- (Store.IncompatibleStore
- Store.StoreCompatibilityMalformed{}) ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected malformed result: " <> show other)
- Right (_startup, store) -> do
- Store.closeStore store
- assertFailure "malformed metadata was accepted"
-
-rejectsCompatibleIncompleteSchema :: Assertion
-rejectsCompatibleIncompleteSchema =
- withStoreFixture "felix-store-incomplete" \path theory _fixture -> do
- (_startup, store) <- expectOpen path theory
- Store.closeStore store
- connection <- SQLite.open path
- SQLite.execute_ connection
- "DROP TABLE canonical_propositions"
- SQLite.close connection
-
- result <- Store.openStore path theory
- case result of
- Left
- (Store.FatalStoreStartup
- Store.StoreSchemaIntegrityFailure{}) ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected incomplete-schema result: " <> show other)
- Right (_startup, current) -> do
- Store.closeStore current
- assertFailure "incomplete current schema was accepted"
-
-rollsBackUnequalDuplicateBatch :: Assertion
-rollsBackUnequalDuplicateBatch =
- withStoreFixture "felix-store-rollback" \path theory fixture -> do
- (_startup, store) <- expectOpen path theory
- let first = fixtureFirstObject fixture
- second = fixtureSecondObject fixture
- prefix <- makePendingPrefix fixture [first, second]
- Store.closeStore store
-
- connection <- SQLite.open path
- SQLite.execute connection
- "INSERT INTO canonical_objects (object_id, payload) VALUES (?, ?)"
- ( Cache.encodeCache
- (Identity.putObjectIdCache
- (Identity.assertedObjectId second))
- , Cache.encodeCache
- (Identity.putObjectContentCache
- (Identity.assertedObjectContent
- first))
- )
- SQLite.close connection
-
- (_reopened, current) <- expectOpen path theory
- result <- Store.writePendingModulePrefix current prefix
- case result of
- Left Store.StoreRowPayloadMismatch{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected duplicate result: " <> show other)
- Right () ->
- assertFailure "unequal duplicate was accepted"
- assertEqual "earlier insertion was rolled back" 0
- =<< storedObjectCount path (Identity.assertedObjectId first)
- Store.closeStore current
-
-rejectsMalformedCanonicalPayloads :: Assertion
-rejectsMalformedCanonicalPayloads =
- withStoreFixture "felix-store-decode" \path theory fixture -> do
- (_startup, store) <- expectOpen path theory
- let object = fixtureFirstObject fixture
- (_owner, prefix, syntax, semantic, key, artifact, _proposition) <-
- makeCommittedModule theory fixture
- expectRightIO
- (Store.writeSealedModule
- store prefix [syntax] [semantic] artifact)
- Store.closeStore store
-
- connection <- SQLite.open path
- SQLite.execute connection
- "UPDATE canonical_objects SET payload = ? \
- \WHERE object_id = ?"
- ( ByteString.singleton 0xff
- , Cache.encodeCache
- (Identity.putObjectIdCache
- (Identity.assertedObjectId object))
- )
- SQLite.close connection
-
- (_reopened, current) <- expectOpen path theory
- memo <- Store.newStoreMemo current
- result <- Store.loadCachedModuleInstallation
- memo current key (Syntax.moduleSyntaxAssertedId syntax)
- case result of
- Left Store.StoreRowDecodeFailure{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected malformed-row result: " <> show other)
- Right _ ->
- assertFailure "malformed canonical payload was accepted"
- Store.closeStore current
-
-plansPersistentStores :: Assertion
-plansPersistentStores =
- Temp.withSystemTempDirectory "felix-store-planning" \root -> do
- (theory, _fixture) <- makeStoreFixture
- let cacheRoot = root Posix.</> "cache"
- expectedDefault =
- cacheRoot Posix.</> "felix" Posix.</> "store.sqlite"
- explicitParent = root Posix.</> "explicit"
- explicitPath = explicitParent Posix.</> "selected.sqlite"
- Directory.createDirectory cacheRoot
- Directory.createDirectory explicitParent
- withEnvironment "XDG_CACHE_HOME" cacheRoot do
- defaultPlan <- expectRightIO
- (Store.planStore Store.DefaultStore)
- defaultResult <- Store.withStoreLease defaultPlan \lease -> do
- assertEqual "default store path"
- expectedDefault
- (Store.storePathFilePath
- (Store.storeLeasePath lease))
- assertBool "planning does not create the default parent"
- . not
- =<< Directory.doesPathExist
- (cacheRoot Posix.</> "felix")
- Store.withOpenStore lease theory \_startup _store ->
- Directory.doesFileExist expectedDefault
- assertEqual "default store opens at the XDG path"
- (Right True) defaultResult
-
- explicitPlan <- expectRightIO
- (Store.planStore
- (Store.ExplicitStore explicitPath))
- explicitResult <- Store.withStoreLease explicitPlan \lease -> do
- assertEqual "explicit store path"
- explicitPath
- (Store.storePathFilePath
- (Store.storeLeasePath lease))
- Store.withOpenStore lease theory \_startup _store ->
- Directory.doesFileExist explicitPath
- assertEqual "explicit store opens without creating its parent"
- (Right True) explicitResult
-
- missing <- Store.planStore
- (Store.ExplicitStore
- (root Posix.</> "missing" Posix.</> "store.sqlite"))
- case missing of
- Left Store.ExplicitStoreParentMissing{} ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected missing-parent result: " <> show other)
- Right _ ->
- assertFailure "missing explicit parent was accepted"
-
-cleansFreshStores :: Assertion
-cleansFreshStores = do
- (theory, _fixture) <- makeStoreFixture
- plan <- expectRightIO
- (Store.planStore Store.FreshTemporaryStore)
-
- successPath <- IORef.newIORef Nothing
- success <- Store.withStoreLease plan \lease -> do
- let path = Store.storePathFilePath
- (Store.storeLeasePath lease)
- IORef.writeIORef successPath (Just path)
- Store.withOpenStore lease theory \_startup _store ->
- Directory.doesFileExist path
- assertEqual "fresh store opened" (Right True) success
- assertFreshRemoved successPath
-
- failurePath <- IORef.newIORef Nothing
- failed <- Exception.try
- (Store.withStoreLease plan \lease -> do
- let path = Store.storePathFilePath
- (Store.storeLeasePath lease)
- IORef.writeIORef failurePath (Just path)
- void
- (Store.withOpenStore lease theory \_startup _store ->
- ioError (userError "fresh action failed")))
- :: IO (Either IOError ())
- case failed of
- Left _ ->
- pure ()
- Right () ->
- assertFailure "fresh-store action exception did not escape"
- assertFreshRemoved failurePath
-
-doesNotFallBackAfterFatalStartup :: Assertion
-doesNotFallBackAfterFatalStartup =
- Temp.withSystemTempDirectory "felix-store-no-fallback" \root -> do
- (theory, _fixture) <- makeStoreFixture
- let persistentParent = root Posix.</> "persistent"
- persistentPath = persistentParent Posix.</> "store.sqlite"
- cacheRoot = root Posix.</> "cache"
- Directory.createDirectory persistentParent
- Directory.createDirectory cacheRoot
- plan <- expectRightIO
- (Store.planStore
- (Store.ExplicitStore persistentPath))
- initialized <- Store.withStoreLease plan \lease ->
- Store.withOpenStore lease theory \_startup _store ->
- pure ()
- assertEqual "fixture store initialized"
- (Right ()) initialized
- connection <- SQLite.open persistentPath
- SQLite.execute_ connection
- "DROP TABLE canonical_objects"
- SQLite.close connection
-
- withEnvironment "XDG_CACHE_HOME" cacheRoot do
- result <- Store.withStoreLease plan \lease ->
- Store.withOpenStore lease theory \_startup _store ->
- pure ()
- case result of
- Left
- (Store.StoreLifecycleOpenFailed
- (Store.FatalStoreStartup
- Store.StoreSchemaIntegrityFailure{})) ->
- pure ()
- Left other ->
- assertFailure
- ("unexpected fatal-startup result: " <> show other)
- Right () ->
- assertFailure "corrupt persistent store was accepted"
- assertBool "fatal startup creates no default fallback"
- . not
- =<< Directory.doesPathExist
- (cacheRoot Posix.</> "felix")
-
-
-data StoreFixture = StoreFixture
- !Identity.AssertedObject
- !Identity.AssertedObject
- !Identity.CheckedPropositionContent
-
-fixtureFirstObject :: StoreFixture -> Identity.AssertedObject
-fixtureFirstObject (StoreFixture object _second _proposition) =
- object
-
-fixtureSecondObject :: StoreFixture -> Identity.AssertedObject
-fixtureSecondObject (StoreFixture _first object _proposition) =
- object
-
-fixtureProposition
- :: StoreFixture
- -> Identity.CheckedPropositionContent
-fixtureProposition (StoreFixture _first _second proposition) =
- proposition
-
-makeStoreFixture
- :: IO (Identity.TheoryId, StoreFixture)
-makeStoreFixture = do
- foundation <- expectRight Foundation.checkedFoundation
- let theory = Identity.theoryId foundation
- first = intrinsicObject theory Core.Empty
- second = intrinsicObject theory Core.PairSet
- closure <- expectRight
- (Identity.validateObjectClosure theory [first, second])
- proposition <- expectRight
- (Identity.validatePropositionContent
- closure
- (Core.CEq
- Core.TySet
- (Core.CGlobal (Identity.assertedObjectId first))
- (Core.CGlobal (Identity.assertedObjectId first))))
- pure
- ( theory
- , StoreFixture first second proposition
- )
-
-intrinsicObject
- :: Identity.TheoryId
- -> Core.CoreIntrinsicTag
- -> Identity.AssertedObject
-intrinsicObject theory tag =
- Identity.assertedObject identity content
- where
- coreType = Core.coreIntrinsicType tag
- content =
- Identity.IntrinsicObjectContent
- theory tag coreType
- identity =
- Identity.intrinsicObjectId
- theory tag coreType
-
-withStoreFixture
- :: String
- -> ( FilePath
- -> Identity.TheoryId
- -> StoreFixture
- -> IO a
- )
- -> IO a
-withStoreFixture template action =
- Temp.withSystemTempDirectory template \root -> do
- (theory, fixture) <- makeStoreFixture
- action
- (root Posix.</> "store.sqlite")
- theory
- fixture
-
-expectOpen
- :: FilePath
- -> Identity.TheoryId
- -> IO (Store.StoreStartup, Store.Store)
-expectOpen path theory = do
- result <- Store.openStore path theory
- case result of
- Left failure ->
- assertFailure (show failure) >> fail "unreachable"
- Right opened ->
- pure opened
-
-expectRight :: Show failure => Either failure value -> IO value
-expectRight = \case
- Left failure ->
- assertFailure (show failure) >> fail "unreachable"
- Right value ->
- pure value
-
-expectRightIO
- :: Show failure
- => IO (Either failure value)
- -> IO value
-expectRightIO action =
- expectRight =<< action
-
-assertFreshRemoved :: IORef.IORef (Maybe FilePath) -> Assertion
-assertFreshRemoved pathReference = do
- selected <- IORef.readIORef pathReference
- case selected of
- Nothing ->
- assertFailure "fresh store path was not allocated"
- Just path -> do
- assertBool "fresh database was removed"
- . not
- =<< Directory.doesPathExist path
- assertBool "fresh database directory was removed"
- . not
- =<< Directory.doesPathExist
- (Posix.takeDirectory path)
-
-withEnvironment
- :: String
- -> String
- -> IO value
- -> IO value
-withEnvironment name value action =
- Exception.bracket
- (Environment.lookupEnv name)
- restore
- \_previous -> do
- Environment.setEnv name value
- action
- where
- restore = \case
- Nothing ->
- Environment.unsetEnv name
- Just previous ->
- Environment.setEnv name previous
diff --git a/source/Test/Unit/Token.hs b/source/Test/Unit/Token.hs
deleted file mode 100644
index d399e2a..0000000
--- a/source/Test/Unit/Token.hs
+++ /dev/null
@@ -1,285 +0,0 @@
-{-# LANGUAGE OverloadedStrings #-}
-
-module Test.Unit.Token (unitTests) where
-
-import Base
-import Report.Location
-import Syntax.Adapt
-import Syntax.Abstract (Associativity(..))
-import Syntax.Interface
-import Syntax.Pragma
-import Syntax.Token
-
-import Data.Text qualified as Text
-import Test.Tasty
-import Test.Tasty.HUnit
-import Text.Megaparsec (errorBundlePretty)
-
-unitTests :: TestTree
-unitTests = testGroup "Lexer"
- [ testCase "nested math inside text returns to text" nestedMathInsideText
- , testCase "nested text and math returns to the enclosing frame" deeperAlternation
- , testCase "braces inside text do not close the text frame" textBraceNesting
- , testCase "cases is tokenized as an environment only inside math" casesOnlyInsideMath
- , testCase "imports retain source locations and POSIX spellings" locatedImports
- , testCase "commented environment starts are ignored"
- ignoresCommentedEnvironmentStart
- , testCase "empty inputs construct empty lexical syntax"
- constructsEmptyLexicalSyntax
- , testCase "extracts exact source fixity pragmas"
- extractsSourceFixityPragmas
- , testCase "rejects malformed reserved pragma lines"
- rejectsMalformedPragmas
- ]
-
-nestedMathInsideText :: Assertion
-nestedMathInsideText = do
- tokens <- tokensInProof "$\\text{if $x \\in A$ then}$"
- tokens `shouldBe`
- [ BeginEnv "proof"
- , BeginEnv "math"
- , BeginEnv "text"
- , Word "if"
- , BeginEnv "math"
- , Variable "x"
- , Command "in"
- , Variable "A"
- , EndEnv "math"
- , Word "then"
- , EndEnv "text"
- , EndEnv "math"
- , EndEnv "proof"
- ]
-
-deeperAlternation :: Assertion
-deeperAlternation = do
- tokens <- tokensInProof "$\\text{a $ \\text{b $c$ d} e$ f}$"
- tokens `shouldBe`
- [ BeginEnv "proof"
- , BeginEnv "math"
- , BeginEnv "text"
- , Word "a"
- , BeginEnv "math"
- , BeginEnv "text"
- , Word "b"
- , BeginEnv "math"
- , Variable "c"
- , EndEnv "math"
- , Word "d"
- , EndEnv "text"
- , Variable "e"
- , EndEnv "math"
- , Word "f"
- , EndEnv "text"
- , EndEnv "math"
- , EndEnv "proof"
- ]
-
-textBraceNesting :: Assertion
-textBraceNesting = do
- tokens <- tokensInProof "$\\text{a {b}}$"
- tokens `shouldBe`
- [ BeginEnv "proof"
- , BeginEnv "math"
- , BeginEnv "text"
- , Word "a"
- , InvisibleBraceL
- , Word "b"
- , InvisibleBraceR
- , EndEnv "text"
- , EndEnv "math"
- , EndEnv "proof"
- ]
-
-casesOnlyInsideMath :: Assertion
-casesOnlyInsideMath = do
- tokensInsideMath <- tokensInProof "$\\begin{cases}x\\end{cases}$"
- tokensInsideMath `shouldBe`
- [ BeginEnv "proof"
- , BeginEnv "math"
- , BeginEnv "cases"
- , Variable "x"
- , EndEnv "cases"
- , EndEnv "math"
- , EndEnv "proof"
- ]
-
- tokensOutsideMath <- tokensInProof "\\begin{cases}x\\end{cases}"
- assertBool
- "cases should not be tokenized as an environment outside math"
- (BeginEnv "cases" `notElem` tokensOutsideMath && EndEnv "cases" `notElem` tokensOutsideMath)
-
-locatedImports :: Assertion
-locatedImports = do
- let raw = Text.unlines
- [ "% heading"
- , "\\import{set/base.tex}"
- , "\\import{set\\special.tex}"
- , "\\begin{axiom}"
- , " $x = x$."
- , "\\end{axiom}"
- ]
- case gatherImports (FileId maxBound) "import-unit" raw of
- Left err ->
- assertFailure (errorBundlePretty err)
- Right imports@[firstImport, secondImport] -> do
- assertEqual
- "import paths"
- ["set/base.tex", "set\\special.tex"]
- (unLocated <$> imports)
- assertEqual "first import line" 2 (locLine (startPos firstImport))
- assertEqual "second import line" 3 (locLine (startPos secondImport))
- Right imports ->
- assertFailure ("expected two imports, got " <> show imports)
-
-ignoresCommentedEnvironmentStart :: Assertion
-ignoresCommentedEnvironmentStart = do
- let raw = Text.unlines
- [ "% \\begin{signature}"
- , "ordinary text"
- , "\\begin{struct}"
- , " an ordered set $X$ is a onesorted structure."
- , "\\end{struct}"
- ]
- (_, chunks) <-
- either
- (assertFailure . errorBundlePretty)
- pure
- (runLexer (FileId maxBound) "commented-environment" raw)
- case chunks of
- [Located{unLocated = BeginEnv "struct"} : _] -> pure ()
- _ -> assertFailure ("expected the real structure environment, got " <> show chunks)
-
-constructsEmptyLexicalSyntax :: Assertion
-constructsEmptyLexicalSyntax =
- forM_
- [ ("empty", "")
- , ("comment-only", "% heading\n% body")
- ]
- \(description, raw) -> do
- let input = Text.pack raw
- imports <-
- either
- (assertFailure . errorBundlePretty)
- pure
- (gatherImports
- (FileId maxBound)
- description
- input)
- assertEqual (description <> " imports") [] imports
- (lexedImports, chunks) <-
- either
- (assertFailure . errorBundlePretty)
- pure
- (runLexer
- (FileId maxBound)
- description
- input)
- assertEqual (description <> " lexer imports") [] lexedImports
- assertEqual (description <> " chunks") [] chunks
- scanned <-
- either
- (assertFailure . show)
- pure
- (concat <$> traverse scanChunk chunks)
- assertEqual (description <> " scanned declarations") [] scanned
- delta <-
- either
- (assertFailure . show)
- pure
- (canonicalSyntaxDelta [])
- assertBool
- (description <> " syntax declarations")
- (null (canonicalSyntaxDeltaEntries delta))
-
-extractsSourceFixityPragmas :: Assertion
-extractsSourceFixityPragmas = do
- let input =
- " %! infixl 0\n"
- <> "\t%! infixr 07\r\n"
- <> "%! infix 3"
- ordinaryComments =
- Text.unlines
- [ "% ! infixl 1"
- , "text %! infixr 2"
- , "% ordinary"
- ]
- pragmas <-
- either
- (assertFailure . Text.unpack . renderSyntaxPragmaError)
- pure
- (extractSyntaxPragmas
- (FileId maxBound)
- "pragma-unit"
- input)
- assertEqual
- "normalized pragmas"
- [ (LeftAssoc, 0, 1, 3)
- , (RightAssoc, 7, 2, 2)
- , (NonAssoc, 3, 3, 1)
- ]
- [ ( syntaxPragmaAssociativity pragma
- , sourceMixfixLevelValue (syntaxPragmaLevel pragma)
- , locLine (syntaxPragmaLocation pragma)
- , locColumn (syntaxPragmaLocation pragma)
- )
- | pragma <- pragmas
- ]
- assertEqual
- "ordinary comments"
- (Right [])
- (extractSyntaxPragmas
- (FileId maxBound)
- "pragma-unit"
- ordinaryComments)
-
-rejectsMalformedPragmas :: Assertion
-rejectsMalformedPragmas =
- forM_
- [ ("%!infixl 1\n", SyntaxPragmaMissingSpaceAfterPrefix)
- , ("%!\n", SyntaxPragmaMissingKeyword)
- , ("%! Infixl 1\n", SyntaxPragmaUnknownKeyword "Infixl")
- , ("%! infixl\n", SyntaxPragmaMissingLevel)
- , ("%! infixl -1\n", SyntaxPragmaInvalidLevel)
- , ("%! infixl ١\n", SyntaxPragmaInvalidLevel)
- , ("%! infixl 8\n", SyntaxPragmaLevelOutOfRange)
- , ("%! infixl 1 extra\n", SyntaxPragmaTrailingContent)
- , ("%! infixl 1\r", SyntaxPragmaLoneCarriageReturn)
- ]
- \(input, expectedProblem) ->
- case extractSyntaxPragmas
- (FileId maxBound)
- "pragma-unit"
- input of
- Left (InvalidSyntaxPragma location actualProblem) -> do
- assertEqual
- ("problem for " <> show input)
- expectedProblem
- actualProblem
- assertEqual "error line" 1 (locLine location)
- assertEqual "error column" 1 (locColumn location)
- Left err ->
- assertFailure
- ("unexpected pragma error: "
- <> Text.unpack (renderSyntaxPragmaError err))
- Right pragmas ->
- assertFailure
- ("expected malformed pragma rejection, got "
- <> show pragmas)
-
-tokensInProof :: Text -> IO [Token]
-tokensInProof raw =
- case runLexer (FileId maxBound) "lexer-unit" wrapped of
- Left err ->
- assertFailure (errorBundlePretty err)
- Right (_imports, chunks) ->
- pure (concatMap (map unLocated) chunks)
- where
- wrapped = Text.unlines
- [ "\\begin{proof}"
- , raw
- , "\\end{proof}"
- ]
-
-shouldBe :: (Eq a, Show a, HasCallStack) => a -> a -> Assertion
-shouldBe = flip (assertEqual "")