diff --git a/AM2RPortHelper.sln b/AM2RPortHelper.sln
index 0eb9db2..48e05e7 100644
--- a/AM2RPortHelper.sln
+++ b/AM2RPortHelper.sln
@@ -17,6 +17,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AM2RPortHelperGUI.Wpf", "AM
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UndertaleModLib", "UndertaleModTool\UndertaleModLib\UndertaleModLib.csproj", "{F402FD71-4FF4-4E2E-ADCD-A45FBDAFD713}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AM2RPortHelperTests", "AM2RPortHelperTests\AM2RPortHelperTests.csproj", "{716D3686-423D-4618-8769-03982463AD04}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -55,6 +57,10 @@ Global
{F402FD71-4FF4-4E2E-ADCD-A45FBDAFD713}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F402FD71-4FF4-4E2E-ADCD-A45FBDAFD713}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F402FD71-4FF4-4E2E-ADCD-A45FBDAFD713}.Release|Any CPU.Build.0 = Release|Any CPU
+ {716D3686-423D-4618-8769-03982463AD04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {716D3686-423D-4618-8769-03982463AD04}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {716D3686-423D-4618-8769-03982463AD04}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {716D3686-423D-4618-8769-03982463AD04}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/AM2RPortHelperTests/AM2RPortHelperTests.csproj b/AM2RPortHelperTests/AM2RPortHelperTests.csproj
new file mode 100644
index 0000000..3ba9ff2
--- /dev/null
+++ b/AM2RPortHelperTests/AM2RPortHelperTests.csproj
@@ -0,0 +1,37 @@
+
+
+
+ net7.0
+ enable
+ enable
+
+ false
+
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
+
+ Always
+
+
+ Always
+
+
+
+
diff --git a/AM2RPortHelperTests/GameLin.zip b/AM2RPortHelperTests/GameLin.zip
new file mode 100644
index 0000000..056e5c5
Binary files /dev/null and b/AM2RPortHelperTests/GameLin.zip differ
diff --git a/AM2RPortHelperTests/GameWin.zip b/AM2RPortHelperTests/GameWin.zip
new file mode 100644
index 0000000..8e2dbf4
Binary files /dev/null and b/AM2RPortHelperTests/GameWin.zip differ
diff --git a/AM2RPortHelperTests/RawModsTests.cs b/AM2RPortHelperTests/RawModsTests.cs
new file mode 100644
index 0000000..1ddbf1b
--- /dev/null
+++ b/AM2RPortHelperTests/RawModsTests.cs
@@ -0,0 +1,150 @@
+using System.Diagnostics;
+using System.IO.Compression;
+using AM2RPortHelperLib;
+using UndertaleModLib.Decompiler;
+using Xunit;
+using Xunit.Abstractions;
+
+namespace AM2RPortHelperTests;
+
+public class RawModsTests
+{
+ //TODO: write tests for mac later
+
+ private readonly string testTempDir;
+ private readonly string libTempDir = Path.GetTempPath() + "/PortHelper/";
+ private readonly ITestOutputHelper output;
+
+ public RawModsTests(ITestOutputHelper output)
+ {
+ Directory.CreateDirectory(libTempDir);
+ testTempDir = Path.GetTempPath() + Guid.NewGuid();
+ this.output = output;
+ }
+
+ #region GetModOSOfRawZipTests
+
+ [Fact]
+ public void WindowsZipWithDifferentRunnerShouldBeWindows()
+ {
+ var result = RawMods.GetModOSOfRawZip("./GameWin.zip");
+ Assert.True(result == Core.ModOS.Windows);
+ }
+
+ [Fact]
+ public void WindowsZipWithSameRunnerShouldBeWindows()
+ {
+ var destinationZip = testTempDir + Guid.NewGuid();
+ ZipFile.ExtractToDirectory("./GameWin.zip", testTempDir);
+ File.Move(testTempDir + "/AM2R Server.exe", testTempDir + "/AM2R.exe");
+ ZipFile.CreateFromDirectory(testTempDir, destinationZip);
+ var result = RawMods.GetModOSOfRawZip(destinationZip);
+ Assert.True(result == Core.ModOS.Windows);
+ }
+
+ [Fact]
+ public void WindowsZipWithTwoRunnersShouldThrow()
+ {
+ var destinationZip = testTempDir + Guid.NewGuid();
+ ZipFile.ExtractToDirectory("./GameWin.zip", testTempDir);
+ File.Copy(testTempDir + "/AM2R Server.exe", testTempDir + "/AM2R.exe");
+ ZipFile.CreateFromDirectory(testTempDir, destinationZip);
+ Assert.Throws(() => RawMods.GetModOSOfRawZip(destinationZip));
+ }
+
+ [Fact]
+ public void LinuxZipWithGoodRunnerShouldBeLinux()
+ {
+ var result = RawMods.GetModOSOfRawZip("./GameLin.zip");
+ Assert.True(result == Core.ModOS.Linux);
+ }
+
+ [Fact]
+ public void LinuxZipWithWrongRunnerShouldThrow()
+ {
+ var destinationZip = Path.GetTempPath() + Guid.NewGuid();
+ ZipFile.ExtractToDirectory("./GameLin.zip", testTempDir);
+ File.Move(testTempDir + "/runner", testTempDir + "/AM2R");
+ ZipFile.CreateFromDirectory(testTempDir, destinationZip);
+ Assert.Throws(() => RawMods.GetModOSOfRawZip(destinationZip));
+ }
+ #endregion
+
+ #region GetProperPathToBuiltinIcons
+
+ [Fact]
+ public void ExistingPathShouldReturnPath()
+ {
+ const string relative = "./GameLin.zip";
+ string absolute = new FileInfo(relative).FullName;
+ string result = RawMods.GetProperPathToBuiltinIcons(nameof(Resources.icon), relative);
+ Assert.True(result == relative);
+ result = RawMods.GetProperPathToBuiltinIcons(nameof(Resources.icon), absolute);
+ Assert.True(result == absolute);
+ }
+
+ [Fact]
+ public void NonExistantPathShouldReturnPathToResource()
+ {
+ string iconPath = libTempDir + "/" + nameof(Resources.icon) + ".png";
+ string result = RawMods.GetProperPathToBuiltinIcons(nameof(Resources.icon), null);
+ Assert.True(result == iconPath);
+ result = RawMods.GetProperPathToBuiltinIcons(nameof(Resources.icon), "/foo");
+ Assert.True(result == iconPath);
+ }
+
+ [Fact]
+ public void NonExistantResourceShouldThrow()
+ {
+ Assert.Throws(() => RawMods.GetProperPathToBuiltinIcons("foo", null));
+ }
+
+ #endregion
+
+ #region PortToWindows
+
+ [Theory]
+ [InlineData("./GameWin.zip")]
+ [InlineData("./GameLin.zip")]
+ public void PortZipToWindows(string inputZip)
+ {
+ var origMod = RawMods.GetModOSOfRawZip(inputZip);
+ var outputZip = testTempDir + Guid.NewGuid();
+ var origExtract = testTempDir + Guid.NewGuid();
+ var newExtract = testTempDir + Guid.NewGuid();
+ RawMods.PortToWindows(inputZip, outputZip);
+ // Our function should see that its a windows zip
+ Assert.True(RawMods.GetModOSOfRawZip(outputZip) == Core.ModOS.Windows);
+ switch (origMod)
+ {
+ case Core.ModOS.Windows:
+ {
+ // File contents should be same between the zips
+ ZipFile.ExtractToDirectory(inputZip, origExtract);
+ ZipFile.ExtractToDirectory(outputZip, newExtract);
+ var origFiles = new DirectoryInfo(origExtract).GetFiles().Select(f => f.Name);
+ var newFiles = new DirectoryInfo(newExtract).GetFiles().Select(f => f.Name);
+ Assert.True(origFiles.SequenceEqual(newFiles));
+ break;
+ }
+ case Core.ModOS.Linux:
+ {
+ // File contents should be same between the zips except for runner missing in original and data file being different
+ ZipFile.ExtractToDirectory(inputZip, origExtract);
+ ZipFile.ExtractToDirectory(outputZip, newExtract);
+ List origFiles = new DirectoryInfo(origExtract + "/assets").GetFiles().Select(f => f.Name).ToList();
+ origFiles.Remove("game.unx");
+ origFiles.Add("data.win");
+ origFiles.Add("AM2R.exe");
+ origFiles.Sort();
+ List newFiles = new DirectoryInfo(newExtract).GetFiles().Select(f => f.Name).ToList();
+ newFiles.Sort();
+ Assert.True(origFiles.SequenceEqual(newFiles));
+ break;
+ }
+ }
+ }
+ #endregion
+
+ // TODO: write tests for porttolinux, porttoandroid, porttomac
+}
\ No newline at end of file