@@ -266,6 +266,40 @@ public void TryBackupExistingSave_ReturnsFalseWithoutErrorWhenSourceDoesNotExist
266266 }
267267 }
268268
269+ [ TestMethod ]
270+ public void TryListBackups_ReturnsProfileBackupsNewestFirst ( )
271+ {
272+ string tempDirectory = CreateTempDirectory ( ) ;
273+ try
274+ {
275+ string savePath = Path . Combine ( tempDirectory , "mod_profiles.json" ) ;
276+ string backupDirectory = Path . Combine ( tempDirectory , "backups" ) ;
277+ Directory . CreateDirectory ( backupDirectory ) ;
278+ string oldBackup = Path . Combine ( backupDirectory , "mod_profiles.20260605-210000.manual.json" ) ;
279+ string newBackup = Path . Combine ( backupDirectory , "mod_profiles.20260606-210000.manual.json" ) ;
280+ string settingsBackup = Path . Combine ( backupDirectory , "mod_settings.20260607-210000.manual.json" ) ;
281+ File . WriteAllText ( oldBackup , "{ \" Profiles\" : [{ \" Name\" : \" Old\" }] }" ) ;
282+ File . WriteAllText ( newBackup , "{ \" Profiles\" : [{ \" Name\" : \" New\" }] }" ) ;
283+ File . WriteAllText ( settingsBackup , "[]" ) ;
284+ File . SetLastWriteTimeUtc ( oldBackup , new DateTime ( 2026 , 6 , 5 , 21 , 0 , 0 , DateTimeKind . Utc ) ) ;
285+ File . SetLastWriteTimeUtc ( newBackup , new DateTime ( 2026 , 6 , 6 , 21 , 0 , 0 , DateTimeKind . Utc ) ) ;
286+ File . SetLastWriteTimeUtc ( settingsBackup , new DateTime ( 2026 , 6 , 7 , 21 , 0 , 0 , DateTimeKind . Utc ) ) ;
287+
288+ bool found = ProfileBackupService . TryListBackups ( savePath , new [ ] { ".json" , ".json5" , ".jsonc" } , out var backups , out string ? error ) ;
289+
290+ Assert . IsTrue ( found , error ) ;
291+ Assert . AreEqual ( 2 , backups . Count ) ;
292+ Assert . AreEqual ( newBackup , backups [ 0 ] . Path ) ;
293+ Assert . AreEqual ( oldBackup , backups [ 1 ] . Path ) ;
294+ StringAssert . Contains ( backups [ 0 ] . Label , "2026-06-06" ) ;
295+ StringAssert . Contains ( backups [ 0 ] . Label , "Manual backup" ) ;
296+ }
297+ finally
298+ {
299+ Directory . Delete ( tempDirectory , true ) ;
300+ }
301+ }
302+
269303 [ TestMethod ]
270304 public void BuildCsv_EscapesExcelFriendlyModExportRows ( )
271305 {
@@ -473,10 +507,12 @@ public void BuildBody_DescribesV16ActionsWithoutRuntimeSpecificInstructions()
473507 string body = TutorialContentBuilder . BuildBody ( ) ;
474508
475509 StringAssert . Contains ( body , "profiles" ) ;
510+ StringAssert . Contains ( body , "Portable Mode" ) ;
476511 StringAssert . Contains ( body , "Backup" ) ;
477512 StringAssert . Contains ( body , "CSV" ) ;
478513 StringAssert . Contains ( body , "Logs" ) ;
479- StringAssert . Contains ( body , "Game" ) ;
514+ StringAssert . Contains ( body , "Load lets you choose" ) ;
515+ Assert . IsFalse ( body . Contains ( "timestamped safety" , StringComparison . OrdinalIgnoreCase ) ) ;
480516 StringAssert . Contains ( body , "cloud behavior stays opt-in" ) ;
481517 }
482518
@@ -688,12 +724,13 @@ public void GetTutorialDialogLayout_UsesReadableTextSize()
688724 {
689725 TutorialDialogLayout layout = ModdingScreenDialogRules . GetTutorialDialogLayout ( ) ;
690726
691- Assert . IsTrue ( layout . PopupWidth >= 1000 ) ;
692- Assert . IsTrue ( layout . PopupHeight >= 700 ) ;
727+ Assert . IsTrue ( layout . PopupWidth <= 900 ) ;
728+ Assert . IsTrue ( layout . PopupHeight <= 640 ) ;
693729 Assert . IsTrue ( layout . ContentWidth < layout . PopupWidth ) ;
694730 Assert . IsTrue ( layout . ContentHeight < layout . PopupHeight ) ;
695- Assert . IsTrue ( layout . ContentHeight >= 560 ) ;
696- Assert . IsTrue ( layout . BodyFontSize >= 24 ) ;
731+ Assert . IsTrue ( layout . ContentWidth <= 720 ) ;
732+ Assert . IsTrue ( layout . ContentHeight >= 480 ) ;
733+ Assert . IsTrue ( layout . BodyFontSize >= 22 ) ;
697734 Assert . IsTrue ( layout . ButtonFontSize >= 24 ) ;
698735 }
699736
@@ -709,7 +746,7 @@ public void FitTutorialDialogToViewport_KeepsDialogInsideInitial1080pWindow()
709746 Assert . IsTrue ( layout . PopupHeight <= 640 ) ;
710747 Assert . IsTrue ( layout . ContentWidth < layout . PopupWidth ) ;
711748 Assert . IsTrue ( layout . ContentHeight < layout . PopupHeight ) ;
712- Assert . IsTrue ( layout . BodyFontSize >= 24 ) ;
749+ Assert . IsTrue ( layout . BodyFontSize >= 22 ) ;
713750 }
714751
715752 [ TestMethod ]
@@ -726,121 +763,6 @@ public void ShouldCreateAutomaticBackup_RunsAutomaticReasonsOnceAndNeverForManua
726763 Assert . IsFalse ( BackupTriggerRules . ShouldCreateAutomaticBackup ( completedReasons , ProfileBackupReason . Manual ) ) ;
727764 }
728765
729- [ TestMethod ]
730- public void TrySelectVersion_SelectsValidatedSteamDbDerivedVersionByName ( )
731- {
732- var entries = new [ ]
733- {
734- new GameVersionEntry
735- {
736- DisplayName = "0.99.1" ,
737- AppId = 2868840 ,
738- DepotId = 2868841 ,
739- ManifestId = 1234567890123456789 ,
740- BuildId = "example"
741- }
742- } ;
743-
744- bool selected = GameVersionSelectionRules . TrySelectVersion ( entries , "0.99.1" , out var entry , out string ? error ) ;
745-
746- Assert . IsTrue ( selected , error ) ;
747- Assert . AreEqual ( ( uint ) 2868840 , entry . AppId ) ;
748- Assert . AreEqual ( ( uint ) 2868841 , entry . DepotId ) ;
749- Assert . AreEqual ( ( ulong ) 1234567890123456789 , entry . ManifestId ) ;
750- }
751-
752- [ TestMethod ]
753- public void TrySelectVersion_RejectsIncompleteSteamDbDerivedVersion ( )
754- {
755- var entries = new [ ]
756- {
757- new GameVersionEntry
758- {
759- DisplayName = "Broken" ,
760- AppId = 2868840 ,
761- DepotId = 0 ,
762- ManifestId = 123
763- }
764- } ;
765-
766- bool selected = GameVersionSelectionRules . TrySelectVersion ( entries , "Broken" , out _ , out string ? error ) ;
767-
768- Assert . IsFalse ( selected ) ;
769- Assert . AreEqual ( "Steam depot id is required." , error ) ;
770- }
771-
772- [ TestMethod ]
773- public void BuildSteamCmdDownloadDepotArguments_UsesAppDepotAndManifestIds ( )
774- {
775- var entry = new GameVersionEntry
776- {
777- DisplayName = "0.99.1" ,
778- AppId = 2868840 ,
779- DepotId = 2868841 ,
780- ManifestId = 1234567890123456789
781- } ;
782-
783- var args = GameVersionSelectionRules . BuildSteamCmdDownloadDepotArguments ( entry , @"C:\Games\STS2-0.99.1" ) ;
784-
785- CollectionAssert . AreEqual ( new [ ]
786- {
787- "+force_install_dir" ,
788- @"C:\Games\STS2-0.99.1" ,
789- "+login" ,
790- "anonymous" ,
791- "+download_depot" ,
792- "2868840" ,
793- "2868841" ,
794- "1234567890123456789" ,
795- "+quit"
796- } , args . ToArray ( ) ) ;
797- }
798-
799- [ TestMethod ]
800- public void TryBuildDownloadPlan_UsesSelectedVersionAndQuotesSteamCmdCommand ( )
801- {
802- var settings = new GameVersionDownloadSettings
803- {
804- Enabled = true ,
805- SteamCmdPath = @"C:\Program Files\steamcmd\steamcmd.exe" ,
806- InstallRootDirectory = @"C:\Games\STS2 Versions" ,
807- SelectedVersion = "0.99.1" ,
808- Versions =
809- [
810- new GameVersionEntry
811- {
812- DisplayName = "0.99.1" ,
813- AppId = 2868840 ,
814- DepotId = 2868841 ,
815- ManifestId = 1234567890123456789
816- }
817- ]
818- } ;
819-
820- bool built = GameVersionSelectionRules . TryBuildDownloadPlan ( settings , out var plan , out string ? error ) ;
821-
822- Assert . IsTrue ( built , error ) ;
823- Assert . AreEqual ( @"C:\Games\STS2 Versions\0.99.1" , plan . InstallDirectory ) ;
824- Assert . AreEqual ( "\" C:\\ Program Files\\ steamcmd\\ steamcmd.exe\" +force_install_dir \" C:\\ Games\\ STS2 Versions\\ 0.99.1\" +login anonymous +download_depot 2868840 2868841 1234567890123456789 +quit" , plan . CommandLine ) ;
825- }
826-
827- [ TestMethod ]
828- public void TryBuildDownloadPlan_RequiresExplicitEnablement ( )
829- {
830- var settings = new GameVersionDownloadSettings
831- {
832- Enabled = false ,
833- SteamCmdPath = "steamcmd" ,
834- InstallRootDirectory = @"C:\Games" ,
835- SelectedVersion = "0.99.1"
836- } ;
837-
838- bool built = GameVersionSelectionRules . TryBuildDownloadPlan ( settings , out _ , out string ? error ) ;
839-
840- Assert . IsFalse ( built ) ;
841- Assert . AreEqual ( "Game version downloads are not enabled." , error ) ;
842- }
843-
844766 [ TestMethod ]
845767 public void ShouldMirror_RequiresEnabledCloudDirectoryAndMatchingKind ( )
846768 {
0 commit comments