33
44module ActionSpec where
55
6+ import Control.Concurrent (MVar , readMVar )
67import qualified Control.Concurrent as C
78import Control.Concurrent.STM
9+ import Control.Monad.IO.Class (MonadIO (.. ))
810import Development.IDE.Graph (shakeOptions )
911import Development.IDE.Graph.Database (shakeNewDatabase ,
10- shakeRunDatabase )
12+ shakeRunDatabase ,
13+ shakeRunDatabaseForKeys )
1114import Development.IDE.Graph.Internal.Database (build , incDatabase )
1215import Development.IDE.Graph.Internal.Key
1316import Development.IDE.Graph.Internal.Types
@@ -16,15 +19,50 @@ import Example
1619import qualified StmContainers.Map as STM
1720import Test.Hspec
1821
22+
23+
1924spec :: Spec
2025spec = do
26+ describe " apply1" $ it " Test build update, Buggy dirty mechanism in hls-graph #4237" $ do
27+ let ruleStep1 :: MVar Int -> Rules ()
28+ ruleStep1 m = addRule $ \ CountRule _old mode -> do
29+ -- depends on ruleSubBranch, it always changed if dirty
30+ _ :: Int <- apply1 SubBranchRule
31+ let r = 1
32+ case mode of
33+ -- it update the built step
34+ RunDependenciesChanged -> do
35+ _ <- liftIO $ C. modifyMVar m $ \ x -> return (x+ 1 , x)
36+ return $ RunResult ChangedRecomputeSame " " r (return () )
37+ -- this won't update the built step
38+ RunDependenciesSame ->
39+ return $ RunResult ChangedNothing " " r (return () )
40+ count <- C. newMVar 0
41+ count1 <- C. newMVar 0
42+ db <- shakeNewDatabase shakeOptions $ do
43+ ruleSubBranch count
44+ ruleStep1 count1
45+ -- bootstrapping the database
46+ _ <- shakeRunDatabase db $ pure $ apply1 CountRule -- count = 1
47+ let child = newKey SubBranchRule
48+ let parent = newKey CountRule
49+ -- instruct to RunDependenciesChanged then CountRule should be recomputed
50+ -- result should be changed 0, build 1
51+ _res1 <- shakeRunDatabaseForKeys (Just [child]) db [apply1 CountRule ] -- count = 2
52+ -- since child changed = parent build
53+ -- instruct to RunDependenciesSame then CountRule should not be recomputed
54+ -- result should be changed 0, build 1
55+ _res3 <- shakeRunDatabaseForKeys (Just [parent]) db [apply1 CountRule ] -- count = 2
56+ -- invariant child changed = parent build should remains after RunDependenciesSame
57+ -- this used to be a bug, with additional computation, see https://github.com/haskell/haskell-language-server/pull/4238
58+ _res3 <- shakeRunDatabaseForKeys (Just [parent]) db [apply1 CountRule ] -- count = 2
59+ c1 <- readMVar count1
60+ c1 `shouldBe` 2
2161 describe " apply1" $ do
2262 it " computes a rule with no dependencies" $ do
23- db <- shakeNewDatabase shakeOptions $ do
24- ruleUnit
63+ db <- shakeNewDatabase shakeOptions ruleUnit
2564 res <- shakeRunDatabase db $
26- pure $ do
27- apply1 (Rule @ () )
65+ pure $ apply1 (Rule @ () )
2866 res `shouldBe` [() ]
2967 it " computes a rule with one dependency" $ do
3068 db <- shakeNewDatabase shakeOptions $ do
@@ -38,8 +76,7 @@ spec = do
3876 ruleBool
3977 let theKey = Rule @ Bool
4078 res <- shakeRunDatabase db $
41- pure $ do
42- apply1 theKey
79+ pure $ apply1 theKey
4380 res `shouldBe` [True ]
4481 Just (Clean res) <- lookup (newKey theKey) <$> getDatabaseValues theDb
4582 resultDeps res `shouldBe` ResultDeps [singletonKeySet $ newKey (Rule @ () )]
@@ -49,14 +86,12 @@ spec = do
4986 ruleBool
5087 let theKey = Rule @ Bool
5188 res <- shakeRunDatabase db $
52- pure $ do
53- apply1 theKey
89+ pure $ apply1 theKey
5490 res `shouldBe` [True ]
5591 Just KeyDetails {.. } <- atomically $ STM. lookup (newKey (Rule @ () )) databaseValues
56- keyReverseDeps `shouldBe` ( singletonKeySet $ newKey theKey)
92+ keyReverseDeps `shouldBe` singletonKeySet ( newKey theKey)
5793 it " rethrows exceptions" $ do
58- db <- shakeNewDatabase shakeOptions $ do
59- addRule $ \ (Rule :: Rule () ) _old _mode -> error " boom"
94+ db <- shakeNewDatabase shakeOptions $ addRule $ \ (Rule :: Rule () ) _old _mode -> error " boom"
6095 let res = shakeRunDatabase db $ pure $ apply1 (Rule @ () )
6196 res `shouldThrow` anyErrorCall
6297 it " computes a rule with branching dependencies does not invoke phantom dependencies #3423" $ do
@@ -81,18 +116,16 @@ spec = do
81116 countRes <- build theDb emptyStack [SubBranchRule ]
82117 snd countRes `shouldBe` [1 :: Int ]
83118
84- describe " applyWithoutDependency" $ do
85- it " does not track dependencies" $ do
86- db@ (ShakeDatabase _ _ theDb) <- shakeNewDatabase shakeOptions $ do
87- ruleUnit
88- addRule $ \ Rule _old _mode -> do
89- [() ] <- applyWithoutDependency [Rule ]
90- return $ RunResult ChangedRecomputeDiff " " True $ return ()
119+ describe " applyWithoutDependency" $ it " does not track dependencies" $ do
120+ db@ (ShakeDatabase _ _ theDb) <- shakeNewDatabase shakeOptions $ do
121+ ruleUnit
122+ addRule $ \ Rule _old _mode -> do
123+ [() ] <- applyWithoutDependency [Rule ]
124+ return $ RunResult ChangedRecomputeDiff " " True $ return ()
91125
92- let theKey = Rule @ Bool
93- res <- shakeRunDatabase db $
94- pure $ do
95- applyWithoutDependency [theKey]
96- res `shouldBe` [[True ]]
97- Just (Clean res) <- lookup (newKey theKey) <$> getDatabaseValues theDb
98- resultDeps res `shouldBe` UnknownDeps
126+ let theKey = Rule @ Bool
127+ res <- shakeRunDatabase db $
128+ pure $ applyWithoutDependency [theKey]
129+ res `shouldBe` [[True ]]
130+ Just (Clean res) <- lookup (newKey theKey) <$> getDatabaseValues theDb
131+ resultDeps res `shouldBe` UnknownDeps
0 commit comments