Relocate concrete UndoManager + AfterUndoMessage into headless Gum.Presentation (ADR-0005 Phase 3)#3357
Merged
Merged
Conversation
…esentation (ADR-0005 Phase 3) First concrete logic class (not just a contract) to cross the headless boundary, unblocked by #3355 (IUndoPluginNotifier) and #3356 (IUndoRenameLogic), which drained UndoManager's last two tool-coupled ctor deps. All 6 ctor deps are now headless interfaces and the body references no tool-only types. - git mv Gum/Undo/UndoManager.cs and AfterUndoMessage.cs -> Tools/Gum.Presentation/Undo/. Namespace stays Gum.Undo, so Builder.cs DI and all consumers (incl. PluginManager's AfterUndoMessage handler) compile unchanged. - Drop now-stale usings Gum.Managers and Gum.Wireframe. - Localize the tool-only StateSave.SetFrom extension as a private UndoManager.SetStateContentsFrom helper (UndoManager was its only caller in the repo); remove the orphan from StateSaveExtensionMethodsGumTool. FixEnumerations is now unconditional, matching prior tool behavior (the extension guarded it with #if GUM, and GUM is defined in the tool build). - Delete the dead GetWhatToApplyTo method and its only-consumer UndoObject.cs. - Grant Gum.Presentation InternalsVisibleTo GumToolUnitTests so UndoManagerTests keeps reaching the internal UndoLocks; Gum.csproj already granted this via AssemblyInfo, so the grant moves with the class. Behavior-preserving. Verified: Gum.Presentation compiles standalone (0 errors, no WPF/WinForms leak); GumFull.sln builds (0 errors); GumToolUnitTests 1000 passed / 0 failed / 4 skipped. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
vchelaru
added a commit
that referenced
this pull request
Jun 25, 2026
…005 Phase 3) (#3358) Stand up the headless test suite that realizes the point of the undo migration: testing undo/redo logic with zero UI. The new Gum.Presentation.Tests project references Gum.Presentation alone (no WPF/WinForms), so a green run proves the relocated UndoManager is fully headless. Migrate the entire UndoManagerTests suite out of the WPF GumToolUnitTests into Gum.Presentation.Tests. All 20 tests port unchanged (only the namespace and base class move) — none secretly needed the tool. They reach UndoManager's internal UndoLocks, and that InternalsVisibleTo grant moved with the class, so the port is minimal-churn. Removed from GumToolUnitTests to avoid duplicates (git detects it as a rename). Add 7 new tests covering core undo/redo branches the ported suite missed, all against mocked ports: empty-history early-outs (CanUndo/CanRedo/PerformUndo), the RequestLock defer-until-disposed contract, redo-stack truncation on a divergent edit, ClearAll, and the post-undo IFileCommands autosave interaction. Add BaseTestClass + TestAssemblyInitialize (DisableTestParallelization, required because the suite uses the StandardElementsManager/ObjectFinder GumCommon singletons), mirroring the headless Gum.ProjectServices.Tests conventions. Wire Gum.Presentation.Tests into AllLibraries.sln (under Tests) and add a Bucket-A CI step next to Gum.ProjectServices.Tests, so the suite keeps running in CI after leaving the GumToolUnitTests job. dotnet sln add also pulled Gum.Presentation in as a first-class AllLibraries project (nested under Tools to match its sibling Gum.ProjectServices). GumFull.sln and Gum.sln were already wired by the move PR (#3357). Drop the now-dead InternalsVisibleTo("GumToolUnitTests") grant from Gum.Presentation.csproj — UndoLocks was the only internal it reached, and that suite moved. Verified: GumFull.sln still builds, GumToolUnitTests still compiles. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Open
11 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Relocates the concrete
UndoManagerclass — the first piece of actual logic, not just a contract — across the headless boundary intoGum.Presentation, plus itsAfterUndoMessage. This is the payoff move of the ADR-0005 Phase 3 undo extraction, unblocked by #3355 (IUndoPluginNotifier) and #3356 (IUndoRenameLogic), which drainedUndoManager's last two tool-coupled constructor dependencies. All 6 ctor deps are now headless interfaces (ISelectedState,IUndoRenameLogic,IGuiCommands,IFileCommands,IMessenger,IUndoPluginNotifier).Changes
git mvGum/Undo/UndoManager.csandAfterUndoMessage.cs→Tools/Gum.Presentation/Undo/. TheGum.Undonamespace is preserved, soBuilder.csDI registration and every consumer (includingPluginManager'sAfterUndoMessagehandler) compile unchanged.Gum.ManagersandGum.Wireframe.StateSave.SetFromextension as a privateUndoManager.SetStateContentsFromhelper. The standalone headless compile surfaced this asUndoManager's last hidden tool-only dependency (it lived in the tool-onlyStateSaveExtensionMethodsGumToolpartial).UndoManagerwas its only caller in the entire repo, so it was never a shared extension; the orphan is removed from the tool partial.FixEnumerations()is now called unconditionally — matching prior tool behavior, where the extension's#if GUM-guarded call was always active (GUMis defined in the tool build).GetWhatToApplyTomethod and its only-consumerUndoObject.cs.Gum.PresentationInternalsVisibleTo("GumToolUnitTests")soUndoManagerTestskeeps reachingUndoManager'sinternal UndoLocks.Gum.csprojalready granted this viaAssemblyInfo.cs, so the grant simply moves with the class.Behavior
Behavior-preserving (move + dead-code deletion + single-caller helper relocation).
Verification
Gum.Presentationcompiles standalone — 0 errors (the headless proof: no WPF/WinForms leak crossed the boundary).GumFull.slnbuilds — 0 errors.GumToolUnitTests— 1000 passed, 0 failed, 4 skipped (incl.UndoManagerTestsandCompositeMemberLogicApplyTests).Follow-up
UndoManagerbeing headless now unlocks headless undo/redo unit tests (no UI needed) in a futureGum.Presentation.Testsproject — theInternalsVisibleTo("Gum.Presentation.Tests")grant is already in place for that.🤖 Generated with Claude Code