packages feed

sydtest-mutation-0.1.0.0: test/Test/Syd/ReorderSpec.hs

{-# LANGUAGE OverloadedStrings #-}

module Test.Syd.ReorderSpec (spec) where

import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.Map.Strict as Map
import qualified Data.Set as Set
import Test.Syd
import Test.Syd.Mutation
import Test.Syd.OptParse (Settings (..), defaultSettings)

spec :: Spec
spec = describe "reorderTestForestByTiming" $ do
  it "orders sibling leaves ascending by baseline" $ do
    forest <-
      execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $ do
        it "a" (pure () :: IO ())
        it "b" (pure () :: IO ())
        it "c" (pure () :: IO ())
    let costs =
          Map.fromList
            [ (TestId (("a", 0) :| []), 30),
              (TestId (("b", 0) :| []), 10),
              (TestId (("c", 0) :| []), 20)
            ]
    map (renderTestId . fst) (flattenTestForestWithIds (reorderTestForestByTiming costs forest))
      `shouldBe` ["b", "c", "a"]

  it "keeps equal-cost and untimed siblings in source order (stable, missing = first)" $ do
    forest <-
      execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $ do
        it "timed-late" (pure () :: IO ())
        it "untimed" (pure () :: IO ())
        it "tie1" (pure () :: IO ())
        it "tie2" (pure () :: IO ())
    let costs =
          Map.fromList
            [ (TestId (("timed-late", 0) :| []), 5),
              (TestId (("tie1", 0) :| []), 5),
              (TestId (("tie2", 0) :| []), 5)
            ]
    map (renderTestId . fst) (flattenTestForestWithIds (reorderTestForestByTiming costs forest))
      `shouldBe` ["untimed", "timed-late", "tie1", "tie2"]

  it "reorders a sequential (parallelism) subtree" $ do
    forest <-
      execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $
        sequential $ do
          it "a" (pure () :: IO ())
          it "b" (pure () :: IO ())
          it "c" (pure () :: IO ())
    let costs =
          Map.fromList
            [ (TestId (("a", 0) :| []), 30),
              (TestId (("b", 0) :| []), 10),
              (TestId (("c", 0) :| []), 20)
            ]
    map (renderTestId . fst) (flattenTestForestWithIds (reorderTestForestByTiming costs forest))
      `shouldBe` ["b", "c", "a"]

  it "leaves a doNotRandomiseExecutionOrder subtree in source order" $ do
    forest <-
      execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $
        doNotRandomiseExecutionOrder $ do
          it "z" (pure () :: IO ())
          it "y" (pure () :: IO ())
          it "x" (pure () :: IO ())
    let costs =
          Map.fromList
            [ (TestId (("z", 0) :| []), 3),
              (TestId (("y", 0) :| []), 1),
              (TestId (("x", 0) :| []), 2)
            ]
    map (renderTestId . fst) (flattenTestForestWithIds (reorderTestForestByTiming costs forest))
      `shouldBe` ["z", "y", "x"]

  it "does not descend into a doNotRandomiseExecutionOrder subtree" $ do
    forest <-
      execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $
        doNotRandomiseExecutionOrder $ do
          it "z" (pure () :: IO ())
          randomiseExecutionOrder $ do
            it "n1" (pure () :: IO ())
            it "n2" (pure () :: IO ())
    let costs =
          Map.fromList
            [ (TestId (("z", 0) :| []), 30),
              (TestId (("n1", 0) :| []), 20),
              (TestId (("n2", 0) :| []), 10)
            ]
    map (renderTestId . fst) (flattenTestForestWithIds (reorderTestForestByTiming costs forest))
      `shouldBe` ["z", "n1", "n2"]

  it "reorders a beforeAll_ group as a unit without splitting its setup" $ do
    forest <-
      execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $ do
        it "outside-mid" (pure () :: IO ())
        beforeAll_ (pure ()) $ do
          it "g-cheap" (pure () :: IO ())
          it "g-expensive" (pure () :: IO ())
    let costs =
          Map.fromList
            [ (TestId (("g-cheap", 0) :| []), 1),
              (TestId (("g-expensive", 0) :| []), 100),
              (TestId (("outside-mid", 0) :| []), 50)
            ]
    -- Source order is [outside-mid, g-cheap, g-expensive].  A leaf-global sort
    -- would interleave "outside-mid" (50) between the group's leaves (1, 100).
    -- Keeping the group as a unit puts it first (min cost 1) and leaves
    -- "outside-mid" after both of its leaves.
    map (renderTestId . fst) (flattenTestForestWithIds (reorderTestForestByTiming costs forest))
      `shouldBe` ["g-cheap", "g-expensive", "outside-mid"]

  it "preserves the set of test ids" $ do
    forest <-
      execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $ do
        describe "g1" $ do
          it "a" (pure () :: IO ())
          it "b" (pure () :: IO ())
        it "c" (pure () :: IO ())
    let costs = Map.fromList [(TestId (("g1", 0) :| [("a", 0)]), 5)]
    Set.fromList (map fst (flattenTestForestWithIds (reorderTestForestByTiming costs forest)))
      `shouldBe` Set.fromList (map fst (flattenTestForestWithIds forest))

  describe "reorderForMutationChild (gate)" $ do
    it "reorders when randomisation is enabled and a baseline is present" $ do
      forest <-
        execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $ do
          it "a" (pure () :: IO ())
          it "b" (pure () :: IO ())
          it "c" (pure () :: IO ())
      let costs =
            Map.fromList
              [ (TestId (("a", 0) :| []), 30),
                (TestId (("b", 0) :| []), 10),
                (TestId (("c", 0) :| []), 20)
              ]
      map (renderTestId . fst) (flattenTestForestWithIds (reorderForMutationChild True (Just costs) forest))
        `shouldBe` ["b", "c", "a"]

    it "leaves the forest untouched when randomisation is disabled" $ do
      forest <-
        execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $ do
          it "a" (pure () :: IO ())
          it "b" (pure () :: IO ())
          it "c" (pure () :: IO ())
      let costs =
            Map.fromList
              [ (TestId (("a", 0) :| []), 30),
                (TestId (("b", 0) :| []), 10),
                (TestId (("c", 0) :| []), 20)
              ]
      map (renderTestId . fst) (flattenTestForestWithIds (reorderForMutationChild False (Just costs) forest))
        `shouldBe` ["a", "b", "c"]

    it "leaves the forest untouched when no baseline is available" $ do
      forest <-
        execTestDefM (defaultSettings {settingRandomiseExecutionOrder = False}) $ do
          it "a" (pure () :: IO ())
          it "b" (pure () :: IO ())
          it "c" (pure () :: IO ())
      map (renderTestId . fst) (flattenTestForestWithIds (reorderForMutationChild True Nothing forest))
        `shouldBe` ["a", "b", "c"]