@@ -56,6 +56,12 @@ import UnitTests.Distribution.Client.ArbitraryInstances
5656tests :: MTimeChange -> [TestTree ]
5757tests mtimeChange =
5858 map
59+ -- Are you tuning performance for these tests? The size of the arbitrary
60+ -- instances involved is very significant, because each element generated
61+ -- corresponds to one or more Git subcommands being run.
62+ --
63+ -- See [Tuning Arbitrary Instances] below for more information and
64+ -- parameters.
5965 (localOption $ QuickCheckTests 10 )
6066 [ ignoreInWindows " See issue #8048 and #9519" $
6167 testGroup
@@ -472,6 +478,7 @@ instance Arbitrary PrngSeed where
472478-- VCS commands to make a repository on-disk.
473479
474480data SubmodulesSupport = SubmodulesSupported | SubmodulesNotSupported
481+ deriving (Show , Eq )
475482
476483class KnownSubmodulesSupport (a :: SubmodulesSupport ) where
477484 submoduleSupport :: SubmodulesSupport
@@ -484,7 +491,11 @@ instance KnownSubmodulesSupport 'SubmodulesNotSupported where
484491
485492data FileUpdate = FileUpdate FilePath String
486493 deriving (Show )
487- data SubmoduleAdd = SubmoduleAdd FilePath FilePath (Commit 'SubmodulesSupported)
494+ data SubmoduleAdd = SubmoduleAdd
495+ { submodulePath :: FilePath
496+ , submoduleSource :: FilePath
497+ , submoduleCommit :: Commit 'SubmodulesSupported
498+ }
488499 deriving (Show )
489500
490501newtype Commit (submodules :: SubmodulesSupport )
@@ -525,40 +536,71 @@ data RepoRecipe submodules
525536genFileName :: Gen FilePath
526537genFileName = (\ c -> " file" </> [c]) <$> choose (' A' , ' E' )
527538
539+ -- [Tuning Arbitrary Instances]
540+ --
541+ -- Arbitrary repo recipes can get quite large due to nesting:
542+ --
543+ -- - `RepoRecipes` contain a number of groups (`TaggedCommits` or `BranchCommits`).
544+ -- - Groups contain a number of `Commit`s.
545+ -- - Commits contain a number of operations (`FileUpdate` or `SubmoduleAdd`).
546+ --
547+ -- There's also another wrinkle in that `SubmoduleAdd`s contain a `Commit`
548+ -- themselves, so square the `operationsPerCommit` number!
549+ --
550+ -- Then, a rough upper bound of the number of `git` calls required for an
551+ -- arbitrary `RepoRecipe` is
552+ -- `groupsPerRecipe * commitsPerGroup * operationsPerCommit^2`.
553+ --
554+ -- The original implementation of these instances, which chose
555+ -- reasonable-sounding size parameters of 5-15, led to a maximum of 1875
556+ -- operations per test case! No wonder they took so long!
557+ --
558+ -- In most cases, we only care about one or many operations, so "two" is a fine
559+ -- stand-in for "many" :)
560+ groupsPerRecipe :: Int
561+ groupsPerRecipe = 3
562+
563+ commitsPerGroup :: Int
564+ commitsPerGroup = 3
565+
566+ operationsPerCommit :: Int
567+ operationsPerCommit = 3
568+
528569instance Arbitrary FileUpdate where
529- arbitrary = genOnlyFileUpdate
570+ arbitrary = FileUpdate <$> genFileName <*> genFileContent
530571 where
531- genOnlyFileUpdate = FileUpdate <$> genFileName <*> genFileContent
532572 genFileContent = vectorOf 10 (choose (' #' , ' ~' ))
533573
534574instance Arbitrary SubmoduleAdd where
535- arbitrary = genOnlySubmoduleAdd
575+ arbitrary = SubmoduleAdd <$> genFileName <*> genSubmoduleSrc <*> arbitrary
536576 where
537- genOnlySubmoduleAdd = SubmoduleAdd <$> genFileName <*> genSubmoduleSrc <*> arbitrary
538577 genSubmoduleSrc = vectorOf 20 (choose (' a' , ' z' ))
539578
540579instance forall submodules . KnownSubmodulesSupport submodules => Arbitrary (Commit submodules ) where
541- arbitrary = Commit <$> shortListOf1 5 fileUpdateOrSubmoduleAdd
580+ arbitrary = Commit <$> shortListOf1 operationsPerCommit (sized fileUpdateOrSubmoduleAdd)
542581 where
543- fileUpdateOrSubmoduleAdd =
582+ fileUpdateOrSubmoduleAdd 0 = Left <$> arbitrary
583+ fileUpdateOrSubmoduleAdd size =
544584 case submoduleSupport @ submodules of
545585 SubmodulesSupported ->
546586 frequency
547587 [ (10 , Left <$> arbitrary)
548- , (1 , Right <$> arbitrary)
588+ , -- A `SubmoduleAdd` contains a `Commit`, so we make sure to scale
589+ -- down the size in the recursive call to avoid unbounded nesting.
590+ (1 , Right <$> resize (size `div` 2 ) arbitrary)
549591 ]
550592 SubmodulesNotSupported -> Left <$> arbitrary
551593 shrink (Commit writes) = Commit <$> filter (not . null ) (shrink writes)
552594
553595instance KnownSubmodulesSupport submodules => Arbitrary (TaggedCommits submodules ) where
554- arbitrary = TaggedCommits <$> genTagName <*> shortListOf1 5 arbitrary
596+ arbitrary = TaggedCommits <$> genTagName <*> shortListOf1 commitsPerGroup arbitrary
555597 where
556598 genTagName = (" tag_" ++ ) <$> shortListOf1 5 (choose (' A' , ' Z' ))
557599 shrink (TaggedCommits tag commits) =
558600 TaggedCommits tag <$> filter (not . null ) (shrink commits)
559601
560602instance KnownSubmodulesSupport submodules => Arbitrary (BranchCommits submodules ) where
561- arbitrary = BranchCommits <$> genBranchName <*> shortListOf1 5 arbitrary
603+ arbitrary = BranchCommits <$> genBranchName <*> shortListOf1 commitsPerGroup arbitrary
562604 where
563605 genBranchName =
564606 sized $ \ n ->
@@ -568,12 +610,12 @@ instance KnownSubmodulesSupport submodules => Arbitrary (BranchCommits submodule
568610 BranchCommits branch <$> filter (not . null ) (shrink commits)
569611
570612instance KnownSubmodulesSupport submodules => Arbitrary (NonBranchingRepoRecipe submodules ) where
571- arbitrary = NonBranchingRepoRecipe <$> shortListOf1 15 arbitrary
613+ arbitrary = NonBranchingRepoRecipe <$> shortListOf1 groupsPerRecipe arbitrary
572614 shrink (NonBranchingRepoRecipe xs) =
573615 NonBranchingRepoRecipe <$> filter (not . null ) (shrink xs)
574616
575617instance KnownSubmodulesSupport submodules => Arbitrary (BranchingRepoRecipe submodules ) where
576- arbitrary = BranchingRepoRecipe <$> shortListOf1 15 taggedOrBranch
618+ arbitrary = BranchingRepoRecipe <$> shortListOf1 groupsPerRecipe taggedOrBranch
577619 where
578620 taggedOrBranch =
579621 frequency
0 commit comments