packages feed

seihou-cli-0.6.0.0: test/Seihou/CLI/UpdateInteractionSpec.hs

module Seihou.CLI.UpdateInteractionSpec (tests) where

import Control.Lens ((^.))
import Data.Generics.Labels ()
import Data.Map.Strict qualified as Map
import Data.Set qualified as Set
import Seihou.CLI.Update (UpdatePlan (..))
import Seihou.CLI.Update.Interaction
  ( InteractionError (..),
    InteractionMode (..),
    ResolutionDecision (..),
    applyResolutionDecisions,
    forceResolveUpdatePlan,
    resolveInteractively,
  )
import Seihou.CLI.UpdateFixture (conflictPlan, orphanPlan, unavailableConflictPlan)
import Seihou.Engine.Reconcile
  ( FileConflictChoice (..),
    FileReconciliation (..),
    OrphanChoice (..),
    ReconciliationPlan (..),
    ResolvedFileConflict (..),
    unresolvedPaths,
  )
import Test.Hspec
import Test.Tasty
import Test.Tasty.Hspec (testSpec)

tests :: IO TestTree
tests = testSpec "Seihou.CLI.Update.Interaction" spec

spec :: Spec
spec = do
  it "refuses unresolved plans in non-interactive mode" $ do
    result <- resolveInteractively NonInteractive conflictPlan
    result `shouldBe` Left (InteractionRequired (Set.singleton "README.md"))

  it "force accepts ordinary generated conflicts" $ do
    resolved <- expectResolved conflictPlan (forceResolveUpdatePlan conflictPlan)
    unresolvedPaths (resolved ^. #reconciliation) `shouldBe` Set.empty
    case Map.lookup "README.md" (resolved ^. #reconciliation . #files) of
      Just (FileConflict _ _ _ _ _ _ (Just choice)) ->
        (choice ^. #choice) `shouldBe` AcceptGenerated
      other -> expectationFailure ("expected resolved conflict, got " <> show other)

  it "force retains edited orphans as tracked state" $ do
    resolved <- expectResolved orphanPlan (forceResolveUpdatePlan orphanPlan)
    case Map.lookup "README.md" (resolved ^. #reconciliation . #files) of
      Just (FileOrphanEdited _ _ _ _ (Just choice)) ->
        choice `shouldBe` RetainTrackedOrphan
      other -> expectationFailure ("expected resolved orphan, got " <> show other)

  it "force leaves merge-driver failures unresolved" $ do
    resolved <- expectResolved unavailableConflictPlan (forceResolveUpdatePlan unavailableConflictPlan)
    unresolvedPaths (resolved ^. #reconciliation) `shouldBe` Set.singleton "README.md"

  it "applies explicit keep-current and detach-orphan choices without writing" $ do
    kept <- expectResolved conflictPlan (applyResolutionDecisions [ResolveFile "README.md" KeepCurrent] conflictPlan)
    case Map.lookup "README.md" (kept ^. #reconciliation . #files) of
      Just (FileConflict _ _ _ _ _ _ (Just choice)) -> (choice ^. #choice) `shouldBe` KeepCurrent
      other -> expectationFailure ("expected keep-current conflict resolution, got " <> show other)
    detached <- expectResolved orphanPlan (applyResolutionDecisions [ResolveOrphan "README.md" DetachAndKeepOrphan] orphanPlan)
    case Map.lookup "README.md" (detached ^. #reconciliation . #files) of
      Just (FileOrphanEdited _ _ _ _ (Just choice)) -> choice `shouldBe` DetachAndKeepOrphan
      other -> expectationFailure ("expected detached orphan resolution, got " <> show other)

expectResolved fallback result = case result of
  Left err -> expectationFailure (show err) >> pure fallback
  Right resolved -> pure resolved