Add Unit Tests to Saradomin Launcher project

This commit is contained in:
dginovker 2023-11-05 19:53:00 +09:00
parent f0e08d2628
commit babd1d3058
10 changed files with 542 additions and 67 deletions

View file

@ -4,6 +4,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Saradomin", "Saradomin\Sara
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Glitonea", "Glitonea\Glitonea.csproj", "{D2884654-2246-4AC0-B53B-5F1DF33DEDD7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UnitTests", "UnitTests\UnitTests.csproj", "{6A66E5A7-9297-410F-B061-EB386679E430}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -18,5 +20,9 @@ Global
{D2884654-2246-4AC0-B53B-5F1DF33DEDD7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D2884654-2246-4AC0-B53B-5F1DF33DEDD7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D2884654-2246-4AC0-B53B-5F1DF33DEDD7}.Release|Any CPU.Build.0 = Release|Any CPU
{6A66E5A7-9297-410F-B061-EB386679E430}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A66E5A7-9297-410F-B061-EB386679E430}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A66E5A7-9297-410F-B061-EB386679E430}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A66E5A7-9297-410F-B061-EB386679E430}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

View file

@ -1,4 +1,8 @@
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<s:String x:Key="/Default/Environment/Hierarchy/Build/BuildTool/CustomBuildToolPath/@EntryValue">/usr/share/dotnet/sdk/7.0.100/MSBuild.dll</s:String>
<s:String x:Key="/Default/Environment/Hierarchy/Build/SolBuilderDuo/UseMsbuildSolutionBuilder/@EntryValue">No</s:String></wpf:ResourceDictionary>
<s:String x:Key="/Default/Environment/Hierarchy/Build/SolBuilderDuo/UseMsbuildSolutionBuilder/@EntryValue">No</s:String>
<s:String x:Key="/Default/Environment/UnitTesting/UnitTestSessionStore/Sessions/=7a951a1e_002Dc4b2_002D4516_002Db0cc_002D72fd4df57b19/@EntryIndexedValue">&lt;SessionState ContinuousTestingMode="0" IsActive="True" Name="All tests from FindMostRecentBackupDirectory.cs" xmlns="urn:schemas-jetbrains-com:jetbrains-ut-session"&gt;
&lt;ProjectFile&gt;6A66E5A7-9297-410F-B061-EB386679E430/d:Saradomin/d:Utilities/d:SingleplayerManagement/f:FindMostRecentBackupDirectory.cs&lt;/ProjectFile&gt;
&lt;/SessionState&gt;</s:String>
</wpf:ResourceDictionary>

View file

@ -3,18 +3,10 @@
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<Version>1.6.0</Version>
</PropertyGroup>
<PropertyGroup>
<TargetPlatform>x64</TargetPlatform>
<PublishSingleFile>true</PublishSingleFile>
<PublishReadyToRun>true</PublishReadyToRun>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<NoWarn>IL2026;CS0067</NoWarn>
<ApplicationIcon>Resources\Icons\saradomin.ico</ApplicationIcon>
<IncludeNativeLibrariesForSelfExtract>true</IncludeNativeLibrariesForSelfExtract>
<StartupObject>Saradomin.Program</StartupObject>
</PropertyGroup>
<PropertyGroup>

View file

@ -28,6 +28,23 @@ namespace Saradomin.Utilities
}
}
public static void OpenFolder(string path)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
Process.Start(new ProcessStartInfo(path) { UseShellExecute = true });
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Console.WriteLine("Opening " + path + "...");
Process.Start("xdg-open", path);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
Process.Start("open", path);
}
}
public static bool IsJavaExecutableValid(string location)
{
try
@ -208,6 +225,11 @@ namespace Saradomin.Utilities
}
}
public static string LocateSingleplayerBackupsHome()
{
return Path.Combine(LocateDefault2009scapeHome(), "singleplayer_backups");
}
public static string LocateSingleplayerHome()
{
return Path.Combine(LocateDefault2009scapeHome(), "singleplayer");

View file

@ -0,0 +1,124 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Saradomin.Utilities;
public static class SingleplayerManagement
{
private static readonly string[] DirsToBackup =
{
"game/data/players",
"game/data/serverstore"
};
private static readonly string[] FilesToBackup =
{
"game/data/eco/ge_resource.emp",
"game/data/eco/grandexchange.db"
};
public static void MakeBackup()
{
if (!Directory.Exists(CrossPlatform.LocateSingleplayerBackupsHome()))
Directory.CreateDirectory(CrossPlatform.LocateSingleplayerBackupsHome());
string timestamp = DateTime.Now.ToString("yyyyMMdd_HHmmss");
string newBackupDir = Path.Combine(
CrossPlatform.LocateSingleplayerBackupsHome(),
timestamp
);
Directory.CreateDirectory(newBackupDir);
foreach (string dir in DirsToBackup)
{
string sourcePath = Path.Combine(CrossPlatform.LocateSingleplayerHome(), dir);
string destPath = Path.Combine(newBackupDir, dir);
CopyDirectory(sourcePath, destPath);
}
foreach (string file in FilesToBackup)
{
string sourceFilePath = Path.Combine(CrossPlatform.LocateSingleplayerHome(), file);
string destFilePath = Path.Combine(newBackupDir, file);
string directoryForFile = Path.GetDirectoryName(destFilePath);
if (!Directory.Exists(directoryForFile))
Directory.CreateDirectory(directoryForFile);
File.Copy(sourceFilePath, destFilePath, true);
}
}
private static void CopyDirectory(string sourceDir, string destinationDir)
{
if (!Directory.Exists(destinationDir))
Directory.CreateDirectory(destinationDir);
foreach (string filePath in Directory.GetFiles(sourceDir))
{
string fileName = Path.GetFileName(filePath);
string destFilePath = Path.Combine(destinationDir, fileName);
File.Copy(filePath, destFilePath, true);
}
foreach (string subDirPath in Directory.GetDirectories(sourceDir))
{
string subDirName = Path.GetFileName(subDirPath);
string destSubDirPath = Path.Combine(destinationDir, subDirName);
// Recurse!
CopyDirectory(subDirPath, destSubDirPath);
}
}
public static string FindMostRecentBackupDirectory(IEnumerable<string> directories)
{
return directories.Select(Path.GetFileName).MaxBy(name => name);
}
public static void ApplyLatestBackup()
{
var backupHome = CrossPlatform.LocateSingleplayerBackupsHome();
var singleplayerHome = CrossPlatform.LocateSingleplayerHome();
// Get all backup directories
var backupDirectories = Directory.GetDirectories(backupHome);
// Find the most recent backup directory by parsing the directory names as dates
string mostRecentBackupDirName = FindMostRecentBackupDirectory(backupDirectories);
if (mostRecentBackupDirName == null)
{
Console.WriteLine("No backups found.");
return;
}
string mostRecentBackupFullPath = Path.Combine(backupHome, mostRecentBackupDirName);
Console.WriteLine($"Most recent backup found: {mostRecentBackupFullPath}");
// Get the list of files in the most recent backup
var filesInBackup = Directory.GetFiles(
mostRecentBackupFullPath,
"*",
SearchOption.AllDirectories
);
foreach (var file in filesInBackup)
{
// Calculate the file's destination path in the singleplayer home directory
var relativePath = file.Substring(mostRecentBackupFullPath.Length)
.TrimStart(Path.DirectorySeparatorChar);
var destFilePath = Path.Combine(singleplayerHome, relativePath);
// Ensure the destination directory exists
var destDirectory = Path.GetDirectoryName(destFilePath);
if (!Directory.Exists(destDirectory))
{
Directory.CreateDirectory(destDirectory);
}
// Copy the file to the destination, overwriting any existing file
File.Copy(file, destFilePath, true);
}
Console.WriteLine("Backup has been successfully applied.");
}
}

View file

@ -13,21 +13,21 @@
<HeaderedContentControl Classes="GroupBox"
DockPanel.Dock="Top"
Header="singleplayer logs"
IsVisible="{Binding IsRunning}"
IsVisible="{Binding ShowLogPanel}"
>
<ScrollViewer HorizontalAlignment="Left"
ClipToBounds="True"
Height="300"
Width="390"
Content="{Binding SingleplayerLogsTextBox}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible" />
<ScrollViewer HorizontalAlignment="Left"
ClipToBounds="True"
Height="300"
Width="390"
Content="{Binding SingleplayerLogsTextBox}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Visible" />
</HeaderedContentControl>
<HeaderedContentControl Classes="GroupBox"
DockPanel.Dock="Top"
Header="singleplayer info"
IsVisible="{Binding !IsRunning}"
IsVisible="{Binding !ShowLogPanel}"
>
<StackPanel Orientation="Vertical">
<TextBlock
@ -157,6 +157,32 @@
ZIndex="9999"
IsEnabled="{Binding CanLaunch}" />
<Button
Margin="0,0,0,0"
Width="140"
Height="25"
BorderBrush="{StaticResource DarkBorderBrush}"
BorderThickness="1"
Classes="OutsideNavigator"
Command="{Binding MakeBackup}"
Opacity="1"
FontSize="11"
Content="Make Backup"
ZIndex="9999"/>
<Button
Margin="0,0,0,0"
Width="140"
Height="25"
BorderBrush="{StaticResource DarkBorderBrush}"
BorderThickness="1"
Classes="OutsideNavigator"
Command="{Binding OpenBackupFolder}"
Opacity="1"
FontSize="11"
Content="Open Backups"
ZIndex="9999" />
<Grid Margin="0,2,0,4"
ColumnDefinitions="*,Auto"
RowDefinitions="Auto,Auto">
@ -180,15 +206,6 @@
Text="{Binding Launcher.InstallationDirectory, Mode=TwoWay}"
Watermark="Enter a path to your preferred installation directory..." />
<Button Grid.Row="1"
Grid.Column="1"
Width="22"
Height="24"
Margin="2,0,0,0"
Classes="OutsideNavigator"
Command="{Binding BrowseForInstallationDirectory}"
Content="..."
ToolTip.Tip="Browse..." />
</Grid>
</StackPanel>

View file

@ -3,17 +3,14 @@ using System.IO;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Layout;
using Avalonia.Media;
using Avalonia.Threading;
using Glitonea.Extensions;
using Glitonea.Mvvm;
using Glitonea.Mvvm.Messaging;
using Saradomin.Infrastructure.Messaging;
using Saradomin.Infrastructure.Services;
using Saradomin.Model.Settings.Launcher;
using Saradomin.Utilities;
using Saradomin.View.Windows;
namespace Saradomin.ViewModel.Controls
{
@ -24,16 +21,16 @@ namespace Saradomin.ViewModel.Controls
public string SingleplayerDownloadText { get; private set; } = "Download Singleplayer";
public bool CanDownload { get; private set; } = true;
public bool CanLaunch => File.Exists(CrossPlatform.LocateSingleplayerExecutable());
public bool IsRunning {get ; private set; }
public bool CanLaunch => File.Exists(CrossPlatform.LocateSingleplayerExecutable()) && !_isRunning;
public TextBox SingleplayerLogsTextBox { get; private set; }
public bool ShowLogPanel {get; private set; }
public LauncherSettings Launcher => _settingsService.Launcher;
private bool _isRunning;
public SingleplayerViewModel(ISettingsService settingsService, ISingleplayerUpdateService iSingleplayerUpdateService)
{
_settingsService = settingsService;
Message.Subscribe<MainViewLoadedMessage>(this, OnMainViewLoaded);
Message.Subscribe<MainViewLoadedMessage>(this, OnMainViewLoaded); // todo test delete
_singleplayerUpdateService = iSingleplayerUpdateService;
_singleplayerUpdateService.SingleplayerDownloadProgressChanged += OnSingleplayerDownloadProgressChanged;
@ -58,6 +55,9 @@ namespace Saradomin.ViewModel.Controls
if (finished)
{
SingleplayerDownloadText = "Download Singleplayer";
PrintLog($"Singleplayer Download/Update complete");
SingleplayerManagement.ApplyLatestBackup();
PrintLog($"Restored progress from last made backup");
return;
}
@ -82,12 +82,27 @@ namespace Saradomin.ViewModel.Controls
public void DownloadSingleplayer()
{
MakeBackup();
PrintLog($"Starting singleplayer download/update...");
_singleplayerUpdateService.DownloadSingleplayer();
Console.WriteLine("Download singleplayer button clicked");
}
public void PrintLog(string message)
public void MakeBackup()
{
PrintLog("Starting backup of player saves and economy files..");
SingleplayerManagement.MakeBackup();
}
public void OpenBackupFolder()
{
if (!Directory.Exists(CrossPlatform.LocateSingleplayerBackupsHome()))
Directory.CreateDirectory(CrossPlatform.LocateSingleplayerBackupsHome());
CrossPlatform.OpenFolder(CrossPlatform.LocateSingleplayerBackupsHome());
}
private void PrintLog(string message)
{
ShowLogPanel = true;
Dispatcher.UIThread.Post(() =>
{
SingleplayerLogsTextBox.Text += message + Environment.NewLine;
@ -96,8 +111,12 @@ namespace Saradomin.ViewModel.Controls
public void LaunchSingleplayer()
{
IsRunning = true;
new Task(() => CrossPlatform.RunCommandAndGetOutput(CrossPlatform.LocateSingleplayerExecutable(), PrintLog, PrintLog)).Start();
_isRunning = true;
new Task(() =>
CrossPlatform.RunCommandAndGetOutput($"{CrossPlatform.LocateSingleplayerExecutable()} {Launcher.JavaExecutableLocation}",
PrintLog,
PrintLog)
).Start();
}
private void LaunchFaq()
@ -109,32 +128,5 @@ namespace Saradomin.ViewModel.Controls
{
CrossPlatform.LaunchURL("https://forum.2009scape.org/viewforum.php?f=8-support");
}
private async Task BrowseForInstallationDirectory()
{
var ofd = new OpenFolderDialog
{
Title = "Browse for Installation Directory...",
Directory = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile)
};
var path = await ofd.ShowAsync(Application.Current.GetMainWindow());
if (path != null)
{
if (CrossPlatform.IsDirectoryWritable(path))
{
Launcher.InstallationDirectory = path;
}
else
{
NotificationBox.DisplayNotification(
"Access denied",
"The location you have selected is not writable. Select the one you have permissions for.",
Application.Current.GetMainWindow()
);
}
}
}
}
}

View file

@ -0,0 +1,294 @@
namespace UnitTests.Saradomin.Utilities.SingleplayerManagement;
[TestFixture]
public class BackupManagerTests
{
[Test]
public void WithValidDirectories_ReturnsMostRecent()
{
// Arrange
var directories = new List<string>
{
"/backups/20230101_120000",
"/backups/20230102_120000",
"/backups/20230103_120000"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20230103_120000".Equals(mostRecent));
}
[Test]
public void WithDifferentYears_ReturnsMostRecent()
{
// Arrange
var directories = new List<string>
{
"/backups/20210101_120000",
"/backups/20220101_120000",
"/backups/20230101_120000"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20230101_120000".Equals(mostRecent));
}
[Test]
public void WithDifferentMonths_ReturnsMostRecent()
{
// Arrange
var directories = new List<string>
{
"/backups/20230101_120000",
"/backups/20230201_120000",
"/backups/20230301_120000"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20230301_120000".Equals(mostRecent));
}
[Test]
public void WithDifferentDays_ReturnsMostRecent()
{
// Arrange
var directories = new List<string>
{
"/backups/20230301_120000",
"/backups/20230302_120000",
"/backups/20230303_120000"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20230303_120000".Equals(mostRecent));
}
[Test]
public void WithDifferentHours_ReturnsMostRecent()
{
// Arrange
var directories = new List<string>
{
"/backups/20230301_110000",
"/backups/20230301_120000",
"/backups/20230301_130000"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20230301_130000".Equals(mostRecent));
}
[Test]
public void WithDifferentMinutes_ReturnsMostRecent()
{
// Arrange
var directories = new List<string>
{
"/backups/20230301_120100",
"/backups/20230301_120200",
"/backups/20230301_120300"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20230301_120300".Equals(mostRecent));
}
[Test]
public void WithDifferentSeconds_ReturnsMostRecent()
{
// Arrange
var directories = new List<string>
{
"/backups/20230301_120000",
"/backups/20230301_120015",
"/backups/20230301_120030"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20230301_120030".Equals(mostRecent));
}
[Test]
public void WithMixedDateTimes_ReturnsMostRecent_Case1()
{
// Arrange
var directories = new List<string>
{
"/backups/20210101_235959",
"/backups/20201231_235959",
"/backups/20220228_235959"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20220228_235959".Equals(mostRecent));
}
[Test]
public void WithMixedDateTimes_ReturnsMostRecent_Case2()
{
// Arrange
var directories = new List<string>
{
"/backups/20211001_000001",
"/backups/20211001_000002",
"/backups/20210930_235959"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20211001_000002".Equals(mostRecent));
}
[Test]
public void WithMixedDateTimes_ReturnsMostRecent_Case3()
{
// Arrange
var directories = new List<string>
{
"/backups/20211231_235959",
"/backups/20220101_000000",
"/backups/20211231_235958"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20220101_000000".Equals(mostRecent));
}
[Test]
public void WithMixedDateTimes_ReturnsMostRecent_Case4()
{
// Arrange
var directories = new List<string>
{
"/backups/20230530_123456",
"/backups/20230529_123456",
"/backups/20220530_123457"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20230530_123456".Equals(mostRecent));
}
[Test]
public void WithMixedDateTimes_ReturnsMostRecent_Case5()
{
// Arrange
var directories = new List<string>
{
"/backups/20230102_010101",
"/backups/20230101_222222",
"/backups/20221231_235959"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20230102_010101".Equals(mostRecent));
}
[Test]
public void WithMixedDateTimes_ReturnsMostRecent_Case6()
{
// Arrange
var directories = new List<string>
{
"/backups/20240101_120000",
"/backups/20231231_235959",
"/backups/20231231_235958"
};
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That("20240101_120000".Equals(mostRecent));
}
[Test]
public void WithNoDirectories_ReturnsNull()
{
// Arrange
var directories = new List<string>();
// Act
var mostRecent =
global::Saradomin.Utilities.SingleplayerManagement.FindMostRecentBackupDirectory(
directories
);
// Assert
Assert.That(mostRecent, Is.EqualTo(null));
}
}

View file

@ -0,0 +1,23 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.2"/>
<PackageReference Include="NUnit" Version="3.13.3"/>
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1"/>
<PackageReference Include="NUnit.Analyzers" Version="3.3.0"/>
<PackageReference Include="coverlet.collector" Version="3.1.2"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Saradomin\Saradomin.csproj" />
</ItemGroup>
</Project>

1
UnitTests/Usings.cs Normal file
View file

@ -0,0 +1 @@
global using NUnit.Framework;