diff --git a/UndertaleModLib.Tests/EmbeddedAudioTest.cs b/UndertaleModLib.Tests/EmbeddedAudioTest.cs new file mode 100644 index 000000000..a800a58ef --- /dev/null +++ b/UndertaleModLib.Tests/EmbeddedAudioTest.cs @@ -0,0 +1,54 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UndertaleModLib.Models; + +namespace UndertaleModLib.Tests +{ + public class EmbeddedAudioTest + { + [Theory] + [InlineData(new byte[] + { + 4, 0, 0, 0, + 252, 253, 254, 255, + } + )] + public void TestUnserialize(byte[] data) + { + using var stream = new MemoryStream(data); + var reader = new UndertaleReader(stream); + var embeddedAudio = new UndertaleEmbeddedAudio(); + + embeddedAudio.Unserialize(reader); + + Assert.True(embeddedAudio.Data.Length == BitConverter.ToInt32(data[..4])); + Assert.Equal(embeddedAudio.Data, data[4..]); + } + + [Theory] + [InlineData(new byte[] + { + 4, 0, 0, 0, + 252, 253, 254, 255 + } + )] + public void TestSerialize(byte[] data) + { + using var stream = new MemoryStream(); + UndertaleEmbeddedAudio audio = new UndertaleEmbeddedAudio() + { + Name = new UndertaleString("foobar"), + Data = data[4..] + }; + var writer = new UndertaleWriter(stream); + + audio.Serialize(writer); + + Assert.True(stream.Length == data.Length); + Assert.Equal(stream.ToArray(), data); + } + } +} diff --git a/UndertaleModTests/GameLoadingTests.cs b/UndertaleModLib.Tests/GameLoadingTests.cs similarity index 55% rename from UndertaleModTests/GameLoadingTests.cs rename to UndertaleModLib.Tests/GameLoadingTests.cs index 9680a1688..dbd58c92c 100644 --- a/UndertaleModTests/GameLoadingTests.cs +++ b/UndertaleModLib.Tests/GameLoadingTests.cs @@ -1,15 +1,13 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.IO; -using System.Security.Cryptography; +using System.Linq; +using System.Text; using System.Threading.Tasks; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using UndertaleModLib; +//using UndertaleModLib; using UndertaleModLib.Decompiler; using UndertaleModLib.Models; -namespace UndertaleModTests +namespace UndertaleModLib.Tests { public abstract class GameLoadingTestBase : GameTestBase { @@ -17,7 +15,7 @@ public GameLoadingTestBase(string path, string md5) : base(path, md5) { } - [TestMethod] + [Fact] public void SaveDataAndCompare() { using (MemoryStream ms = new MemoryStream()) @@ -26,11 +24,11 @@ public void SaveDataAndCompare() ms.Position = 0; string writtenMD5 = GenerateMD5(ms); - Assert.AreEqual(expectedMD5, writtenMD5, "Written file doesn't match read file"); + Assert.True(expectedMD5 == writtenMD5, "Written file doesn't match read file"); } } - [TestMethod] + [Fact] public void DecompileAllScripts() { GlobalDecompileContext context = new GlobalDecompileContext(data, true); @@ -39,7 +37,7 @@ public void DecompileAllScripts() //Console.WriteLine(code.Name.Content); try { - Decompiler.Decompile(code, context); + Decompiler.Decompiler.Decompile(code, context); } catch (Exception e) { @@ -48,7 +46,7 @@ public void DecompileAllScripts() }); } - [TestMethod] + [Fact] public void DisassembleAndReassembleAllScripts() { Parallel.ForEach(data.Code, (code) => @@ -56,7 +54,7 @@ public void DisassembleAndReassembleAllScripts() //Console.WriteLine(code.Name.Content); bool knownBug = false; - foreach(var instr in code.Instructions) + foreach (var instr in code.Instructions) { if (instr.Value?.GetType() == typeof(UndertaleResourceById)) { @@ -82,43 +80,50 @@ public void DisassembleAndReassembleAllScripts() } IList reasm = Assembler.Assemble(disasm, data.Functions, data.Variables, data.Strings); - Assert.AreEqual(code.Instructions.Count, reasm.Count, "Reassembled instruction count didn't match the disassembly for script " + code.Name.Content); - for(int i = 0; i < code.Instructions.Count; i++) + + Assert.True(code.Instructions.Count == reasm.Count, "Reassembled instruction count didn't match the disassembly for script " + code.Name.Content); + + for (int i = 0; i < code.Instructions.Count; i++) { string errMsg = "Instruction at " + code.Instructions[i].Address.ToString("D5") + " didn't match for script: " + code.Name.Content; - Assert.AreEqual(code.Instructions[i].Kind, reasm[i].Kind, errMsg); - Assert.AreEqual(code.Instructions[i].ComparisonKind, reasm[i].ComparisonKind, errMsg); - Assert.AreEqual(code.Instructions[i].Type1, reasm[i].Type1, errMsg); - Assert.AreEqual(code.Instructions[i].Type2, reasm[i].Type2, errMsg); - Assert.AreEqual(code.Instructions[i].TypeInst, reasm[i].TypeInst, errMsg); - Assert.AreEqual(code.Instructions[i].Extra, reasm[i].Extra, errMsg); - Assert.AreEqual(code.Instructions[i].SwapExtra, reasm[i].SwapExtra, errMsg); - Assert.AreEqual(code.Instructions[i].ArgumentsCount, reasm[i].ArgumentsCount, errMsg); - Assert.AreEqual(code.Instructions[i].JumpOffsetPopenvExitMagic, reasm[i].JumpOffsetPopenvExitMagic, errMsg); + + Assert.True(code.Instructions[i].Kind == reasm[i].Kind, errMsg); + Assert.True(code.Instructions[i].ComparisonKind == reasm[i].ComparisonKind, errMsg); + Assert.True(code.Instructions[i].Type1 == reasm[i].Type1, errMsg); + Assert.True(code.Instructions[i].Type2 == reasm[i].Type2, errMsg); + Assert.True(code.Instructions[i].TypeInst == reasm[i].TypeInst, errMsg); + Assert.True(code.Instructions[i].Extra == reasm[i].Extra, errMsg); + Assert.True(code.Instructions[i].SwapExtra == reasm[i].SwapExtra, errMsg); + Assert.True(code.Instructions[i].ArgumentsCount == reasm[i].ArgumentsCount, errMsg); + Assert.True(code.Instructions[i].JumpOffsetPopenvExitMagic == reasm[i].JumpOffsetPopenvExitMagic, errMsg); + if (!code.Instructions[i].JumpOffsetPopenvExitMagic) - Assert.AreEqual(code.Instructions[i].JumpOffset, reasm[i].JumpOffset, errMsg); // note: also handles IntArgument implicitly - Assert.AreSame(code.Instructions[i].Destination?.Target, reasm[i].Destination?.Target, errMsg); - Assert.AreEqual(code.Instructions[i].Destination?.Type, reasm[i].Destination?.Type, errMsg); - Assert.AreSame(code.Instructions[i].Function?.Target, reasm[i].Function?.Target, errMsg); - Assert.AreEqual(code.Instructions[i].Function?.Type, reasm[i].Function?.Type, errMsg); + Assert.True(code.Instructions[i].JumpOffset == reasm[i].JumpOffset, errMsg); // note: also handles IntArgument implicitly + + Assert.True(Object.ReferenceEquals(code.Instructions[i].Destination?.Target, reasm[i].Destination?.Target), errMsg); + Assert.True(code.Instructions[i].Destination?.Type == reasm[i].Destination?.Type, errMsg); + Assert.True(Object.ReferenceEquals(code.Instructions[i].Function?.Target, reasm[i].Function?.Target), errMsg); + Assert.True(code.Instructions[i].Function?.Type == reasm[i].Function?.Type, errMsg); + + Assert.True(Object.ReferenceEquals(code.Instructions[i].Value?.GetType(), reasm[i].Value?.GetType()), errMsg); - Assert.AreEqual(code.Instructions[i].Value?.GetType(), reasm[i].Value?.GetType(), errMsg); if (code.Instructions[i].Value?.GetType() == typeof(double)) - Assert.AreEqual((double)code.Instructions[i].Value, (double)reasm[i].Value, Math.Abs((double)code.Instructions[i].Value) * (1e-5), errMsg); // see issue #53 + Assert.True(Math.Abs((double)code.Instructions[i].Value - (double)reasm[i].Value) + <= (Math.Abs((double)code.Instructions[i].Value) * (1e-5)), errMsg); // see issue #53 else if (code.Instructions[i].Value?.GetType() == typeof(float)) - Assert.AreEqual((float)code.Instructions[i].Value, (float)reasm[i].Value, Math.Abs((float)code.Instructions[i].Value) * (1e-5), errMsg); // see issue #53 + Assert.True(Math.Abs((float)code.Instructions[i].Value - (float)reasm[i].Value) + <= (Math.Abs((float)code.Instructions[i].Value) * (1e-5)), errMsg); // see issue #53 else if (code.Instructions[i].Value?.GetType() == typeof(UndertaleInstruction.Reference)) - Assert.AreSame(((UndertaleInstruction.Reference)code.Instructions[i].Value).Target, ((UndertaleInstruction.Reference)reasm[i].Value).Target, errMsg); + Assert.True(Object.ReferenceEquals(((UndertaleInstruction.Reference)code.Instructions[i].Value).Target, ((UndertaleInstruction.Reference)reasm[i].Value).Target), errMsg); else if (code.Instructions[i].Value?.GetType() == typeof(UndertaleResourceById)) - Assert.AreSame(((UndertaleResourceById)code.Instructions[i].Value).Resource, ((UndertaleResourceById)reasm[i].Value).Resource, errMsg); + Assert.True(Object.ReferenceEquals(((UndertaleResourceById)code.Instructions[i].Value).Resource, ((UndertaleResourceById)reasm[i].Value).Resource), errMsg); else - Assert.AreEqual(code.Instructions[i].Value, reasm[i].Value, errMsg); + Assert.True(code.Instructions[i].Value == reasm[i].Value, errMsg); } }); } } - [TestClass] public class UndertaleLoadingTest : GameLoadingTestBase { public UndertaleLoadingTest() : base(GamePaths.UNDERTALE_PATH, GamePaths.UNDERTALE_MD5) @@ -126,7 +131,6 @@ public UndertaleLoadingTest() : base(GamePaths.UNDERTALE_PATH, GamePaths.UNDERTA } } - [TestClass] public class UndertaleSwitchLoadingTest : GameLoadingTestBase { public UndertaleSwitchLoadingTest() : base(GamePaths.UNDERTALE_SWITCH_PATH, GamePaths.UNDERTALE_SWITCH_MD5) @@ -134,7 +138,6 @@ public UndertaleSwitchLoadingTest() : base(GamePaths.UNDERTALE_SWITCH_PATH, Game } } - [TestClass] public class DeltaruneLoadingTest : GameLoadingTestBase { public DeltaruneLoadingTest() : base(GamePaths.DELTARUNE_PATH, GamePaths.DELTARUNE_MD5) @@ -142,12 +145,9 @@ public DeltaruneLoadingTest() : base(GamePaths.DELTARUNE_PATH, GamePaths.DELTARU } } - - - [TestClass] public class EmptyGameTest { - [TestMethod] + [Fact] public void CreateAndSaveEmptyGame() { UndertaleData data = UndertaleData.CreateNew(); @@ -157,5 +157,4 @@ public void CreateAndSaveEmptyGame() } } } - } diff --git a/UndertaleModLib.Tests/GamePaths.cs b/UndertaleModLib.Tests/GamePaths.cs new file mode 100644 index 000000000..c0526fae7 --- /dev/null +++ b/UndertaleModLib.Tests/GamePaths.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace UndertaleModLib.Tests +{ + static class GamePaths + { + // TODO: Maybe these should be configuration variables? + //public static string UNDERTALE_PATH = @"C:\Program Files (x86)\Steam\steamapps\common\Undertale\data.win"; + public static string UNDERTALE_PATH = @"D:\SteamLibrary\steamapps\common\Undertale\data.win"; + public static string UNDERTALE_MD5 = "5903fc5cb042a728d4ad8ee9e949c6eb"; + public static string UNDERTALE_SWITCH_PATH = @"..\..\..\Test\bin\Debug\switch\game.win"; + public static string UNDERTALE_SWITCH_MD5 = "427520a97db28c87da4220abb3a334c1"; + public static string DELTARUNE_PATH = @"C:\Program Files (x86)\SURVEY_PROGRAM\data.win"; + public static string DELTARUNE_MD5 = "a88a2db3a68c714ca2b1ff57ac08a032"; + } +} diff --git a/UndertaleModTests/GameScriptTests.cs b/UndertaleModLib.Tests/GameScriptTests.cs similarity index 71% rename from UndertaleModTests/GameScriptTests.cs rename to UndertaleModLib.Tests/GameScriptTests.cs index a20b5089d..51fbac103 100644 --- a/UndertaleModTests/GameScriptTests.cs +++ b/UndertaleModLib.Tests/GameScriptTests.cs @@ -1,210 +1,173 @@ using System; using System.Collections.Generic; -using System.IO; using System.Linq; using System.Reflection; -using System.Threading; +using System.Text; using System.Threading.Tasks; using Microsoft.CodeAnalysis.CSharp.Scripting; using Microsoft.CodeAnalysis.Scripting; using Microsoft.CodeAnalysis.Scripting.Hosting; -using Microsoft.VisualStudio.TestTools.UnitTesting; -using UndertaleModLib; using UndertaleModLib.Decompiler; using UndertaleModLib.Models; using UndertaleModLib.Scripting; -namespace UndertaleModTests +namespace UndertaleModLib.Tests { public abstract class GameScriptTestBase : GameTestBase, IScriptInterface { - public GameScriptTestBase(string path, string md5) : base(path, md5) + protected GameScriptTestBase(string path, string md5) : base(path, md5) { } - public UndertaleData Data => data; - public string FilePath => path; - public object Highlighted => throw new NotImplementedException(); - public object Selected => throw new NotImplementedException(); - public bool CanSave => throw new NotImplementedException(); - public string ScriptPath => throw new NotImplementedException(); - public bool ScriptExecutionSuccess => throw new NotImplementedException(); - public string ScriptErrorMessage => throw new NotImplementedException(); - public string ExePath => throw new NotImplementedException(); - public string ScriptErrorType => throw new NotImplementedException(); - public bool GMLCacheEnabled => throw new NotImplementedException(); + protected async Task RunScript(string path) + { + string scriptpath = Path.Combine("../../../../UndertaleModTool/Scripts/Builtin Scripts/", path); + using (var loader = new InteractiveAssemblyLoader()) + { + loader.RegisterDependency(typeof(UndertaleObject).GetTypeInfo().Assembly); - public bool IsAppClosed => throw new NotImplementedException(); + var script = CSharpScript.Create(File.ReadAllText(scriptpath), ScriptOptions.Default + .WithImports("UndertaleModLib", "UndertaleModLib.Models", "UndertaleModLib.Decompiler", "UndertaleModLib.Scripting", "System", "System.IO", "System.Collections.Generic") + .WithReferences(typeof(UndertaleObject).GetTypeInfo().Assembly), + typeof(IScriptInterface), loader); - public void ChangeSelection(object newSelection) - { + return await script.RunAsync(this); + } } public void EnsureDataLoaded() { } - public async Task MakeNewDataFile() - { - await Task.Delay(1); //dummy await - return true; - } - public void ReplaceTempWithMain(bool imAnExpertBtw = false) - { - } - public void ReplaceMainWithTemp(bool imAnExpertBtw = false) - { - } - public void ReplaceTempWithCorrections(bool imAnExpertBtw = false) - { - } - public void ReplaceCorrectionsWithTemp(bool imAnExpertBtw = false) - { - } - public void UpdateCorrections(bool imAnExpertBtw = false) - { - } - public void ReapplyProfileCode() - { - } - public void InitializeScriptDialog() - { - } - public bool RunUMTScript(string path) + + public bool AreFilesIdentical(string file1, string file2) { - Console.WriteLine(path); + string output = "AreFilesIdentical(): " + file1 + ", " + file2; + Console.Write(output); return true; } - public bool LintUMTScript(string path) + + public bool DummyBool() { - Console.WriteLine(path); return true; } - public void ScriptMessage(string message) + public void DummyVoid() { - Console.WriteLine(message); } - public bool ScriptQuestion(string message) - { - Console.WriteLine(message); - return true; - } - public void ScriptOpenURL(string url) - { - Console.WriteLine("Open: " + url); - } - public void NukeProfileGML(string codeName) - { - Console.WriteLine("NukeProfileGML(): " + codeName); - } - public void UpdateProgressBar(string message, string status, double progressValue, double maxValue) - { - Console.WriteLine("UpdateProgressBar(): " + progressValue + " / " + maxValue + ", Message: " + message + ", Status: " + status); - } - public void SetProgressBar(string message, string status, double progressValue, double maxValue) - { - Console.WriteLine("SetProgressBar(): " + progressValue + " / " + maxValue + ", Message: " + message + ", Status: " + status); - } - public void SetProgressBar() - { - Console.WriteLine("SetProgressBar()"); - } - public void UpdateProgressValue(double progressValue) - { - Console.WriteLine($"UpdateProgressValue(): {progressValue}"); - } - public void UpdateProgressStatus(string status) + public string DummyString() { - Console.WriteLine($"UpdateProgressStatus(): {status}"); + return ""; } + public UndertaleData Data => data; + + public string FilePath => path; + + public string ScriptPath => throw new NotImplementedException(); + + public object Highlighted => throw new NotImplementedException(); + + public object Selected => throw new NotImplementedException(); + + public bool CanSave => throw new NotImplementedException(); + + public bool ScriptExecutionSuccess => throw new NotImplementedException(); + + public string ScriptErrorMessage => throw new NotImplementedException(); + + public string ExePath => throw new NotImplementedException(); + + public string ScriptErrorType => throw new NotImplementedException(); + + public bool GMLCacheEnabled => throw new NotImplementedException(); + + public bool IsAppClosed => throw new NotImplementedException(); + public void AddProgress(int amount) { Console.WriteLine($"AddProgress(): {amount}"); } - public void IncrementProgress() - { - Console.WriteLine("IncrementProgress()"); - } + public void AddProgressParallel(int amount) { Console.WriteLine($"AddProgressParallel(): {amount}"); } - public void IncrementProgressParallel() - { - Console.WriteLine("IncrementProgressParallel()"); - } - public int GetProgress() - { - Console.WriteLine("GetProgress()"); - return -1; - } - public void SetProgress(int value) - { - Console.WriteLine($"SetProgress(): {value}"); - } - - public string ScriptInputDialog(string title, string label, string defaultInput, string cancelText, string submitText, bool isMultiline, bool preventClose) - { - Console.Write(label + " "); - string ret = Console.ReadLine(); - return ret; - } - public string SimpleTextInput(string titleText, string labelText, string defaultInputBoxText, bool isMultiline, bool showDialog = true) - { - return ScriptInputDialog(titleText, labelText, defaultInputBoxText, "Cancel", "Submit", isMultiline, false); - } - public void SimpleTextOutput(string titleText, string labelText, string message, bool isMultiline) + public void ChangeSelection(object newSelection, bool inNewTab = false) { - Console.WriteLine($"SimpleTextOutput(): \"{titleText}\", \"{labelText}\", *defaultInputBoxText* (length - {message.Length}), {isMultiline}"); + Console.WriteLine($"ChangeSelection(): {newSelection}, {inNewTab}"); } - public async Task ClickableSearchOutput(string title, string query, int resultsCount, IOrderedEnumerable>> resultsDict, bool showInDecompiledView, IOrderedEnumerable failedList = null) + + public async Task ClickableSearchOutput(string title, string query, int resultsCount, IOrderedEnumerable>> resultsDict, bool showInDecompiledView, IOrderedEnumerable? failedList = null) { Console.WriteLine($"ClickableSearchOutput(): \"{title}\", \"{query}\", {resultsCount}, *resultsDict* (length - {resultsDict.Count()}), {showInDecompiledView.ToString().ToLower()}" - + failedList is not null ? $", *failedList* (length - {failedList.Count()})" : string.Empty); + + (failedList is not null ? $", *failedList* (length - {failedList.Count()})" : string.Empty)); await Task.Delay(1); //dummy await } - public async Task ClickableSearchOutput(string title, string query, int resultsCount, IDictionary> resultsDict, bool showInDecompiledView, IEnumerable failedList = null) + + public async Task ClickableSearchOutput(string title, string query, int resultsCount, IDictionary> resultsDict, bool showInDecompiledView, IEnumerable? failedList = null) { Console.WriteLine($"ClickableSearchOutput(): \"{title}\", \"{query}\", {resultsCount}, *resultsDict* (length - {resultsDict.Count}), {showInDecompiledView.ToString().ToLower()}" - + failedList is not null ? $", *failedList* (length - {failedList.Count()})" : string.Empty); + + (failedList is not null ? $", *failedList* (length - {failedList.Count()})" : string.Empty)); await Task.Delay(1); //dummy await } - public void SetUMTConsoleText(string message) + public void DisableAllSyncBindings() { - Console.Write("SetUMTConsoleText(): " + message); + Console.WriteLine($"Disabling all enabled synced bindings."); } - public void ReplaceTextInGML(string codeName, string keyword, string replacement, bool caseSensitive = false, bool isRegex = false, GlobalDecompileContext context = null) + + public void EnableUI() { - Console.Write("ReplaceTextInGML(): " + codeName + ", " + keyword + ", " + replacement + ", " + caseSensitive.ToString() + ", " + isRegex.ToString() + ", " + context?.ToString()); + Console.WriteLine("Enabling UI."); } - public void ReplaceTextInGML(UndertaleCode code, string keyword, string replacement, bool caseSensitive = false, bool isRegex = false, GlobalDecompileContext context = null) + + public async Task GenerateGMLCache(ThreadLocal? decompileContext = null, object? dialog = null, bool clearGMLEditedBefore = false) { - Console.Write("ReplaceTextInGML(): " + code.ToString() + ", " + keyword + ", " + replacement + ", " + caseSensitive.ToString() + ", " + isRegex.ToString() + ", " + context?.ToString()); + Console.WriteLine(String.Format("GenerateGMLCache(): *decompileContext*{0}, *dialog*{1}, {2}", + decompileContext is null ? " (null)" : "", + dialog is null ? " (null)" : "", + clearGMLEditedBefore.ToString().ToLower()) + ); + + await Task.Delay(1); //dummy await + + return false; } - public void ImportGMLString(string codeName, string gmlCode, bool doParse = true, bool checkDecompiler = false) + + public string GetDecompiledText(string codeName, GlobalDecompileContext context = null) { - Console.Write("ImportGMLString(): " + codeName + ", " + gmlCode + ", " + doParse.ToString()); + string output = "GetDecompiledText(): " + codeName; + Console.Write(output); + return output; } - public void ImportASMString(string codeName, string gmlCode, bool doParse = true, bool nukeProfile = true, bool checkDecompiler = false) + + public string GetDecompiledText(UndertaleCode code, GlobalDecompileContext context = null) { - Console.Write("ImportASMString(): " + codeName + ", " + gmlCode + ", " + doParse.ToString()); + string output = "GetDecompiledText(): " + code?.ToString(); + Console.Write(output); + return output; } - public void ImportGMLFile(string fileName, bool doParse = true, bool checkDecompiler = false, bool throwOnError = false) + + public string GetDisassemblyText(string codeName) { - Console.Write($"ImportGMLFile(): \"{fileName}\", {doParse}, {checkDecompiler}, {throwOnError}"); + string output = "GetDisassemblyText(): " + codeName; + Console.Write(output); + return output; } - public void ImportASMFile(string fileName, bool doParse = true, bool nukeProfile = true, bool checkDecompiler = false, bool throwOnError = false) + + public string GetDisassemblyText(UndertaleCode code) { - Console.Write($"ImportASMFile(): \"{fileName}\", {doParse}, {nukeProfile}, {checkDecompiler}, {throwOnError}"); + string output = "GetDisassemblyText(): " + code?.ToString(); + Console.Write(output); + return output; } - public void SetFinishedMessage(bool isFinishedMessageEnabled) + public int GetProgress() { - Console.Write("SetFinishedMessage(): " + isFinishedMessageEnabled.ToString()); + Console.WriteLine("GetProgress()"); + return -1; } public void HideProgressBar() @@ -212,60 +175,55 @@ public void HideProgressBar() Console.WriteLine("Hiding Progress Bar."); } - public void EnableUI() + public void ImportASMFile(string fileName, bool doParse = true, bool nukeProfile = true, bool checkDecompiler = false, bool throwOnError = false) { - Console.WriteLine("Enabling UI."); + Console.Write($"ImportASMFile(): \"{fileName}\", {doParse}, {nukeProfile}, {checkDecompiler}, {throwOnError}"); } - public void SyncBinding(string resourceType, bool enable) + + public void ImportASMString(string codeName, string gmlCode, bool doParse = true, bool nukeProfile = true, bool checkDecompiler = false) { - Console.WriteLine($"SyncBinding(): \"{resourceType}\", {enable}"); + Console.Write("ImportASMString(): " + codeName + ", " + gmlCode + ", " + doParse.ToString()); } - public void DisableAllSyncBindings() + + public void ImportGMLFile(string fileName, bool doParse = true, bool checkDecompiler = false, bool throwOnError = false) { - Console.WriteLine($"Disabling all enabled synced bindings."); + Console.Write($"ImportGMLFile(): \"{fileName}\", {doParse}, {checkDecompiler}, {throwOnError}"); } - public void StartProgressBarUpdater() + + public void ImportGMLString(string codeName, string gmlCode, bool doParse = true, bool checkDecompiler = false) { - Console.WriteLine("Starting progress bar updater..."); + Console.Write("ImportGMLString(): " + codeName + ", " + gmlCode + ", " + doParse.ToString()); } - public async Task StopProgressBarUpdater() + + public void IncrementProgress() { - Console.WriteLine("Stopping progress bar updater..."); - await Task.Delay(1); //dummy await + Console.WriteLine("IncrementProgress()"); } - public async Task GenerateGMLCache(ThreadLocal decompileContext = null, object dialog = null, bool clearGMLEditedBefore = false) + public void IncrementProgressParallel() { - Console.WriteLine(String.Format("GenerateGMLCache(): *decompileContext*{0}, *dialog*{1}, {2}", - decompileContext is null ? " (null)" : "", - dialog is null ? " (null)" : "", - clearGMLEditedBefore.ToString().ToLower()) - ); - - await Task.Delay(1); //dummy await - - return false; + Console.WriteLine("IncrementProgressParallel()"); } - protected async Task RunScript(string path) + public void InitializeScriptDialog() { - string scriptpath = Path.Combine("../../../UndertaleModTool/Scripts/Builtin Scripts/", path); - using (var loader = new InteractiveAssemblyLoader()) - { - loader.RegisterDependency(typeof(UndertaleObject).GetTypeInfo().Assembly); + } - var script = CSharpScript.Create(File.ReadAllText(scriptpath), ScriptOptions.Default - .WithImports("UndertaleModLib", "UndertaleModLib.Models", "UndertaleModLib.Decompiler", "UndertaleModLib.Scripting", "System", "System.IO", "System.Collections.Generic") - .WithReferences(typeof(UndertaleObject).GetTypeInfo().Assembly), - typeof(IScriptInterface), loader); + public bool LintUMTScript(string path) + { + Console.WriteLine(path); + return true; + } - return await script.RunAsync(this); - } + public async Task MakeNewDataFile() + { + await Task.Delay(1); //dummy await + return true; } - public void ScriptError(string error, string title = "Error", bool SetConsoleText = true) + public void NukeProfileGML(string codeName) { - throw new NotImplementedException(); + Console.WriteLine("NukeProfileGML(): " + codeName); } public string PromptChooseDirectory() @@ -273,208 +231,206 @@ public string PromptChooseDirectory() throw new NotImplementedException(); } - public string GetDecompiledText(string codeName, GlobalDecompileContext context = null) + public string PromptLoadFile(string defaultExt, string filter) { - string output = "GetDecompiledText(): " + codeName; - Console.Write(output); - return output; + throw new NotImplementedException(); } - public string GetDecompiledText(UndertaleCode code, GlobalDecompileContext context = null) + + public void ReapplyProfileCode() { - string output = "GetDecompiledText(): " + code?.ToString(); - Console.Write(output); - return output; } - public string GetDisassemblyText(string codeName) + + public void ReplaceCorrectionsWithTemp(bool imAnExpertBtw = false) { - string output = "GetDisassemblyText(): " + codeName; - Console.Write(output); - return output; } - public string GetDisassemblyText(UndertaleCode code) + + public void ReplaceMainWithTemp(bool imAnExpertBtw = false) { - string output = "GetDisassemblyText(): " + code?.ToString(); - Console.Write(output); - return output; } - public bool AreFilesIdentical(string file1, string file2) + + public void ReplaceTempWithCorrections(bool imAnExpertBtw = false) { - string output = "AreFilesIdentical(): " + file1 + ", " + file2; - Console.Write(output); - return true; } - public string PromptLoadFile(string defaultExt, string filter) + + public void ReplaceTempWithMain(bool imAnExpertBtw = false) { - throw new NotImplementedException(); } - public bool DummyBool() + + public void ReplaceTextInGML(string codeName, string keyword, string replacement, bool caseSensitive = false, bool isRegex = false, GlobalDecompileContext context = null) { - return true; + Console.Write("ReplaceTextInGML(): " + codeName + ", " + keyword + ", " + replacement + ", " + caseSensitive.ToString() + ", " + isRegex.ToString() + ", " + context?.ToString()); } - public void DummyVoid() + public void ReplaceTextInGML(UndertaleCode code, string keyword, string replacement, bool caseSensitive = false, bool isRegex = false, GlobalDecompileContext context = null) { + Console.Write("ReplaceTextInGML(): " + code.ToString() + ", " + keyword + ", " + replacement + ", " + caseSensitive.ToString() + ", " + isRegex.ToString() + ", " + context?.ToString()); } - public string DummyString() + + public bool RunUMTScript(string path) { - return ""; + Console.WriteLine(path); + return true; } - } - [TestClass] - public class UndertaleScriptTest : GameScriptTestBase - { - public UndertaleScriptTest() : base(GamePaths.UNDERTALE_PATH, GamePaths.UNDERTALE_MD5) + public void ScriptError(string error, string title = "Error", bool SetConsoleText = true) { + throw new NotImplementedException(); } - [TestMethod] - public async Task EnableDebug() + public string ScriptInputDialog(string title, string label, string defaultInput, string cancelText, string submitText, bool isMultiline, bool preventClose) { - await RunScript("EnableDebug.csx"); + Console.Write(label + " "); + // Probably a bad idea + // string ret = Console.ReadLine(); + // return ret; + return ""; } - [TestMethod] - public async Task DebugToggler() + public void ScriptMessage(string message) { - await RunScript("DebugToggler.csx"); + Console.WriteLine(message); } - [TestMethod] - public async Task GoToRoom() + public void ScriptOpenURL(string url) { - await RunScript("GoToRoom.csx"); + Console.WriteLine("Open: " + url); } - [TestMethod] - public async Task ShowRoomName() + public bool ScriptQuestion(string message) { - await RunScript("ShowRoomName.csx"); + Console.WriteLine(message); + return true; } - [TestMethod] - [Ignore] // TODO: path problems - public async Task BorderEnabler() + public void SetFinishedMessage(bool isFinishedMessageEnabled) { - await RunScript("BorderEnabler.csx"); + Console.Write("SetFinishedMessage(): " + isFinishedMessageEnabled.ToString()); } - [TestMethod] - public async Task testing() + public void SetProgress(int value) { - await RunScript("testing.csx"); + Console.WriteLine($"SetProgress(): {value}"); } - [TestMethod] - public async Task RoomOfDetermination() + public void SetProgressBar(string message, string status, double progressValue, double maxValue) { - await RunScript("RoomOfDetermination.csx"); + Console.WriteLine("SetProgressBar(): " + progressValue + " / " + maxValue + ", Message: " + message + ", Status: " + status); } - [TestMethod] - public async Task TTFFonts() + public void SetProgressBar() { - await RunScript("TTFFonts.csx"); + Console.WriteLine("SetProgressBar()"); } - [TestMethod] - public async Task MixMod() + public void SetUMTConsoleText(string message) { - await RunScript("MixMod.csx"); + Console.Write("SetUMTConsoleText(): " + message); } - } - [TestClass] - public class UndertaleSwitchScriptTest : GameScriptTestBase - { - public UndertaleSwitchScriptTest() : base(GamePaths.UNDERTALE_SWITCH_PATH, GamePaths.UNDERTALE_SWITCH_MD5) + public string SimpleTextInput(string title, string label, string defaultValue, bool allowMultiline, bool showDialog = true) { + return ScriptInputDialog(title, label, defaultValue, "Cancel", "Submit", allowMultiline, false); } - [TestMethod] - public async Task EnableDebug() + public void SimpleTextOutput(string title, string label, string message, bool allowMultiline) { - await RunScript("EnableDebug.csx"); + Console.WriteLine($"SimpleTextOutput(): \"{title}\", \"{label}\", *defaultInputBoxText* (length - {message.Length}), {allowMultiline}"); } - [TestMethod] - public async Task DebugToggler() + public void StartProgressBarUpdater() { - await RunScript("DebugToggler.csx"); + Console.WriteLine("Starting progress bar updater..."); } - [TestMethod] - public async Task GoToRoom() + public async Task StopProgressBarUpdater() { - await RunScript("GoToRoom.csx"); + Console.WriteLine("Stopping progress bar updater..."); + await Task.Delay(1); //dummy await } - [TestMethod] - public async Task ShowRoomName() + public void SyncBinding(string resourceType, bool enable) { - await RunScript("ShowRoomName.csx"); + Console.WriteLine($"SyncBinding(): \"{resourceType}\", {enable}"); } - } - [TestClass] - public class DeltaruneScriptTest : GameScriptTestBase - { - public DeltaruneScriptTest() : base(GamePaths.DELTARUNE_PATH, GamePaths.DELTARUNE_MD5) + public void UpdateCorrections(bool imAnExpertBtw = false) { } - [TestMethod] - public async Task EnableDebug() + public void UpdateProgressBar(string message, string status, double progressValue, double maxValue) { - await RunScript("EnableDebug.csx"); + Console.WriteLine("UpdateProgressBar(): " + progressValue + " / " + maxValue + ", Message: " + message + ", Status: " + status); } - [TestMethod] - public async Task DebugToggler() + public void UpdateProgressStatus(string status) { - await RunScript("DebugToggler.csx"); + Console.WriteLine($"UpdateProgressStatus(): {status}"); } - [TestMethod] - public async Task GoToRoom() + public void UpdateProgressValue(double progressValue) { - await RunScript("GoToRoom.csx"); + Console.WriteLine($"UpdateProgressValue(): {progressValue}"); } + } - [TestMethod] - public async Task ShowRoomName() + public class UndertaleScriptTest : GameScriptTestBase + { + public UndertaleScriptTest() : base(GamePaths.UNDERTALE_PATH, GamePaths.UNDERTALE_MD5) { - await RunScript("ShowRoomName.csx"); } - [TestMethod] - public async Task DeltaHATE() + [Theory] + [InlineData("EnableDebug.csx")] + [InlineData("DebugToggler.csx")] + [InlineData("GoToRoom.csx")] + [InlineData("ShowRoomName.csx")] + [InlineData("BorderEnabler.csx")] + [InlineData("testing.csx")] + [InlineData("RoomOfDetermination.csx")] + [InlineData("TTFFonts.csx")] + [InlineData("MixMod.csx")] + public async Task RunScriptTest(string scriptName) { - await RunScript("DeltaHATE.csx"); + await RunScript(scriptName); } + } - [TestMethod] - public async Task DeltaMILK() + public class UndertaleSwitchScriptTest : GameScriptTestBase + { + public UndertaleSwitchScriptTest() : base(GamePaths.UNDERTALE_SWITCH_PATH, GamePaths.UNDERTALE_SWITCH_MD5) { - await RunScript("DeltaMILK.csx"); } - [TestMethod] - public async Task TheWholeWorldRevolving() + [Theory] + [InlineData("EnableDebug.csx")] + [InlineData("DebugToggler.csx")] + [InlineData("GoToRoom.csx")] + [InlineData("ShowRoomName.csx")] + public async Task RunScriptTest(string scriptName) { - await RunScript("TheWholeWorldRevolving.csx"); + await RunScript(scriptName); } + } - [TestMethod] - public async Task DebugMsg() + public class DeltaruneScriptTest : GameScriptTestBase + { + public DeltaruneScriptTest() : base(GamePaths.DELTARUNE_PATH, GamePaths.DELTARUNE_MD5) { - await RunScript("DebugMsg.csx"); } - [TestMethod] - public async Task HeCanBeEverywhere() + [Theory] + [InlineData("EnableDebug.csx")] + [InlineData("DebugToggler.csx")] + [InlineData("GoToRoom.csx")] + [InlineData("ShowRoomName.csx")] + [InlineData("DeltaHATE.csx")] + [InlineData("DeltaMILK.csx")] + [InlineData("TheWholeWorldRevolving.csx")] + [InlineData("DebugMsg.csx")] + [InlineData("HeCanBeEverywhere.csx")] + public async Task RunScriptTest(string scriptName) { - await RunScript("HeCanBeEverywhere.csx"); + await RunScript(scriptName); } } -} + } \ No newline at end of file diff --git a/UndertaleModLib.Tests/GameTestBase.cs b/UndertaleModLib.Tests/GameTestBase.cs new file mode 100644 index 000000000..5430442e4 --- /dev/null +++ b/UndertaleModLib.Tests/GameTestBase.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; + +namespace UndertaleModLib.Tests +{ + public abstract class GameTestBase + { + protected string path; + protected string expectedMD5; + protected UndertaleData data; + + public GameTestBase(string path, string md5) + { + this.path = path; + this.expectedMD5 = md5; + + if (!File.Exists(path)) + Assert.Fail("Unable to test, file not found: " + path); + + using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) + { + string fileMD5 = GenerateMD5(fs); + if (fileMD5 != expectedMD5) + Assert.Fail("Unable to test, incorrect file: got " + fileMD5 + " expected " + expectedMD5); + fs.Position = 0; + + data = UndertaleIO.Read(fs); + } + } + + protected static string GenerateMD5(Stream stream) + { + using (var md5 = MD5.Create()) + { + var hash = md5.ComputeHash(stream); + return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); + } + } + } +} diff --git a/UndertaleModLib.Tests/StringTest.cs b/UndertaleModLib.Tests/StringTest.cs new file mode 100644 index 000000000..ec2a53a74 --- /dev/null +++ b/UndertaleModLib.Tests/StringTest.cs @@ -0,0 +1,126 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UndertaleModLib.Models; + +namespace UndertaleModLib.Tests +{ + public class StringTest + { + [Theory] + [InlineData("", "")] + [InlineData("\n", "\n")] + [InlineData("\n\r\n\r\n", "\n\r\n\r\n")] + [InlineData("T\nh\ri\"s\\", "T\nh\ri\"s\\")] + [InlineData(@"\n", "\n")] + [InlineData(@"\n\r\n\r\n", "\n\r\n\r\n")] + [InlineData(@"T\nh\ri\""s\\", "T\nh\ri\"s\\")] + public void TestUnescapeText(string text, string expected) + { + var result = UndertaleString.UnescapeText(text); + + Assert.Equal(result, expected); + } + + [Theory] + [InlineData("", "", true)] + [InlineData(" ", "", true)] + [InlineData("HELLO", "hello", true)] + [InlineData("hello", "HELLO", true)] + [InlineData("HEllO", "heLLo", true)] + [InlineData("hello", "world", false)] + [InlineData("world", "hello", false)] + [InlineData(null, null, false)] + [InlineData("hi", null, false)] + [InlineData(null, "null", false)] + public void TestSearchMatches(string text, string substring, bool expected) + { + UndertaleString utString = new UndertaleString(text); + + var result = utString.SearchMatches(substring); + + Assert.Equal(result, expected); + } + + [Theory] + [InlineData("I rule!", new byte[] { 7, 0, 0, 0, 73, 32, 114, 117, 108, 101, 33, 0 })] + [InlineData("{]öÄü¢€ΩФЙw", new byte[] { 20, 0, 0, 0, 123, 93, 195, 182, 195, 132, 195, 188, 194, 162, 226, 130, 172, 206, 169, 208, 164, 208, 153, 119, 0 })] + [InlineData("\ud83d\udc38\ud83d\ude03\ud83e\uddd1\ud83c\udffc\u200d\ud83d\ude80\ud83c\udff4\u200d\u2620\ufe0f", new byte[] { 36, 0, 0, 0, 240, 159, 144, 184, 240, 159, 152, 131, 240, 159, 167, 145, 240, 159, 143, 188, 226, 128, 141, 240, 159, 154, 128, 240, 159, 143, 180, 226, 128, 141, 226, 152, 160, 239, 184, 143, 0 })] + public void TestSerialize(string input, byte[] expected) + { + using var stream = new MemoryStream(); + UndertaleString utString = new UndertaleString(input); + var writer = new UndertaleWriter(stream); + + utString.Serialize(writer); + + Assert.Equal(stream.ToArray(), expected); + } + + [Theory] + [InlineData(new byte[] { 7, 0, 0, 0, 73, 32, 114, 117, 108, 101, 33, 0 }, "I rule!")] + [InlineData(new byte[] { 20, 0, 0, 0, 123, 93, 195, 182, 195, 132, 195, 188, 194, 162, 226, 130, 172, 206, 169, 208, 164, 208, 153, 119, 0 }, "{]öÄü¢€ΩФЙw")] + [InlineData(new byte[] { 36, 0, 0, 0, 240, 159, 144, 184, 240, 159, 152, 131, 240, 159, 167, 145, 240, 159, 143, 188, 226, 128, 141, 240, 159, 154, 128, 240, 159, 143, 180, 226, 128, 141, 226, 152, 160, 239, 184, 143, 0 }, "\ud83d\udc38\ud83d\ude03\ud83e\uddd1\ud83c\udffc\u200d\ud83d\ude80\ud83c\udff4\u200d\u2620\ufe0f")] + public void TestUnserialize(byte[] input, string expected) + { + using var stream = new MemoryStream(input); + var reader = new UndertaleReader(stream); + var utString = new UndertaleString(); + + utString.Unserialize(reader); + + Assert.Equal(utString.Content, expected); + } + + [Fact] + public void TestToStringWithNull() + { + var s = new UndertaleString(); + var result = s.ToString(); + Assert.Equal("\"null\"", result); + } + + [Theory] + [InlineData("", "\"\"")] + [InlineData("\"", "\"\\\"\"")] + [InlineData("Hi", "\"Hi\"")] + [InlineData("This is a string", "\"This is a string\"")] + [InlineData("\"A quote\"", "\"\\\"A quote\\\"\"")] + [InlineData("This string has \"quotes\"", "\"This string has \\\"quotes\\\"\"")] + [InlineData("This string has \n newline", "\"This string has \\n newline\"")] + [InlineData("This string has \r also newline", "\"This string has \\r also newline\"")] + [InlineData("This string has \\ backslashes", "\"This string has \\\\ backslashes\"")] + [InlineData("This \"string\" has \n all \r kinds of \\ stuff", "\"This \\\"string\\\" has \\n all \\r kinds of \\\\ stuff\"")] + [InlineData("Some cool characters: { } = () %$! ß? ´'`@", "\"Some cool characters: { } = () %$! ß? ´'`@\"")] + public void TestToStringWithGMS2(string content, string expected) + { + var s = new UndertaleString(content); + var result = s.ToString(true); + Assert.Equal(expected, result); + } + + [Theory] + [InlineData("", "\"\"")] + [InlineData("\"", "'\"'")] + [InlineData("\"This starts with quotes", "'\"' + \"This starts with quotes\"")] + [InlineData("This ends with quotes\"", "\"This ends with quotes\" + '\"'")] + [InlineData("\"This has quotes in start and end\"", "'\"' + \"This has quotes in start and end\" + '\"'")] + [InlineData("This has quotes \" in middle", "\"This has quotes \" + '\"' + \" in middle\"")] + [InlineData("\"This starts and has \" quotes in middle", "'\"' + \"This starts and has \" + '\"' + \" quotes in middle\"")] + [InlineData("This ends and has \" quotes in middle\"", "\"This ends and has \" + '\"' + \" quotes in middle\" + '\"'")] + [InlineData("\"This starts, has \" quotes in middle and ends\"", "'\"' + \"This starts, has \" + '\"' + \" quotes in middle and ends\" + '\"'")] + [InlineData("Hi", "\"Hi\"")] + [InlineData("This is a string", "\"This is a string\"")] + [InlineData("This string has \n newline", "\"This string has \n newline\"")] + [InlineData("This \"string\" has \n all \r kinds of \\ stuff", "\"This \" + '\"' + \"string\" + '\"' + \" has \n all \r kinds of \\ stuff\"")] + [InlineData("Some cool characters: { } = () %$! ß? ´'`@", "\"Some cool characters: { } = () %$! ß? ´'`@\"")] + public void TestToStringWithGMS1(string content, string expected) + { + var s = new UndertaleString(content); + var result = s.ToString(false); + Assert.Equal(expected, result); + } + } +} diff --git a/UndertaleModLib.Tests/UndertaleModLib.Tests.csproj b/UndertaleModLib.Tests/UndertaleModLib.Tests.csproj new file mode 100644 index 000000000..5a9fc93f4 --- /dev/null +++ b/UndertaleModLib.Tests/UndertaleModLib.Tests.csproj @@ -0,0 +1,29 @@ + + + + net8.0 + enable + enable + + false + true + + + + + + + + + + + + + + + + + + + + diff --git a/UndertaleModLibTests/Models/EmbeddedAudioTest.cs b/UndertaleModLibTests/Models/EmbeddedAudioTest.cs deleted file mode 100644 index 4a77f28a6..000000000 --- a/UndertaleModLibTests/Models/EmbeddedAudioTest.cs +++ /dev/null @@ -1,46 +0,0 @@ -using UndertaleModLib; -using UndertaleModLib.Models; -using Xunit; -using Xunit.Extensions; - -namespace UndertaleModLibTests.Models; - -public class EmbeddedAudioTest -{ - [Theory] - [InlineData(new byte[] - { - 4, 0, 0, 0, - 252, 253, 254, 255, - })] - - public void TestUnserialize(byte[] data) - { - using var stream = new MemoryStream(data); - var reader = new UndertaleReader(stream); - var embeddedAudio = new UndertaleEmbeddedAudio(); - - embeddedAudio.Unserialize(reader); - - Assert.True(embeddedAudio.Data.Length == BitConverter.ToInt32(data[..4])); - Assert.Equal(embeddedAudio.Data, data[4..]); - } - - [Fact] - public void TestSerialize() - { - using var stream = new MemoryStream(); - var fullData = new byte[] { 4, 0, 0, 0, 252, 253, 254, 255 }; - UndertaleEmbeddedAudio audio = new UndertaleEmbeddedAudio() - { - Name = new UndertaleString("foobar"), - Data = fullData[4..] - }; - var writer = new UndertaleWriter(stream); - - audio.Serialize(writer); - - Assert.True(stream.Length == fullData.Length); - Assert.Equal(stream.ToArray(), fullData); - } -} diff --git a/UndertaleModLibTests/Models/StringTest.cs b/UndertaleModLibTests/Models/StringTest.cs deleted file mode 100644 index 456b5a973..000000000 --- a/UndertaleModLibTests/Models/StringTest.cs +++ /dev/null @@ -1,125 +0,0 @@ -using UndertaleModLib; -using UndertaleModLib.Models; -using Xunit; -using Xunit.Abstractions; -using Xunit.Sdk; - -namespace UndertaleModLibTests.Models; - -public class StringTest -{ - [Theory] - [InlineData("", "")] - [InlineData("\n", "\n")] - [InlineData("\n\r\n\r\n", "\n\r\n\r\n")] - [InlineData("T\nh\ri\"s\\", "T\nh\ri\"s\\")] - [InlineData(@"\n", "\n")] - [InlineData(@"\n\r\n\r\n", "\n\r\n\r\n")] - [InlineData(@"T\nh\ri\""s\\", "T\nh\ri\"s\\")] - public void TestUnescapeText(string text, string expected) - { - var result = UndertaleString.UnescapeText(text); - - Assert.Equal(result, expected); - } - - [Theory] - [InlineData("", "", true)] - [InlineData(" ", "", true)] - [InlineData("HELLO", "hello", true)] - [InlineData("hello", "HELLO", true)] - [InlineData("HEllO", "heLLo", true)] - [InlineData("hello", "world", false)] - [InlineData("world", "hello", false)] - [InlineData(null, null, false)] - [InlineData("hi", null, false)] - [InlineData(null, "null", false)] - public void TestSearchMatches(string text, string substring, bool expected) - { - UndertaleString utString = new UndertaleString(text); - - var result = utString.SearchMatches(substring); - - Assert.Equal(result, expected); - } - - [Theory] - [InlineData("I rule!", new byte[] {7, 0, 0, 0, 73, 32, 114, 117, 108, 101, 33, 0})] - [InlineData("{]öÄü¢€ΩФЙw", new byte[] {20, 0, 0, 0, 123, 93, 195, 182, 195, 132, 195, 188, 194, 162, 226, 130, 172, 206, 169, 208, 164, 208, 153, 119, 0})] - [InlineData("\ud83d\udc38\ud83d\ude03\ud83e\uddd1\ud83c\udffc\u200d\ud83d\ude80\ud83c\udff4\u200d\u2620\ufe0f", new byte[] {36, 0, 0, 0, 240, 159, 144, 184, 240, 159, 152, 131, 240, 159, 167, 145, 240, 159, 143, 188, 226, 128, 141, 240, 159, 154, 128, 240, 159, 143, 180, 226, 128, 141, 226, 152, 160, 239, 184, 143, 0})] - public void TestSerialize(string input, byte[] expected) - { - using var stream = new MemoryStream(); - UndertaleString utString = new UndertaleString(input); - var writer = new UndertaleWriter(stream); - - utString.Serialize(writer); - - Assert.Equal(stream.ToArray(), expected); - } - - [Theory] - [InlineData(new byte[] {7, 0, 0, 0, 73, 32, 114, 117, 108, 101, 33, 0}, "I rule!")] - [InlineData(new byte[] {20, 0, 0, 0, 123, 93, 195, 182, 195, 132, 195, 188, 194, 162, 226, 130, 172, 206, 169, 208, 164, 208, 153, 119, 0}, "{]öÄü¢€ΩФЙw")] - [InlineData(new byte[] {36, 0, 0, 0, 240, 159, 144, 184, 240, 159, 152, 131, 240, 159, 167, 145, 240, 159, 143, 188, 226, 128, 141, 240, 159, 154, 128, 240, 159, 143, 180, 226, 128, 141, 226, 152, 160, 239, 184, 143, 0}, "\ud83d\udc38\ud83d\ude03\ud83e\uddd1\ud83c\udffc\u200d\ud83d\ude80\ud83c\udff4\u200d\u2620\ufe0f")] - - public void TestUnserialize(byte[] input, string expected) - { - using var stream = new MemoryStream(input); - var reader = new UndertaleReader(stream); - var utString = new UndertaleString(); - - utString.Unserialize(reader); - - Assert.Equal(utString.Content, expected); - } - - [Fact] - public void TestToStringWithNull() - { - var s = new UndertaleString(); - var result = s.ToString(); - Assert.Equal("\"null\"", result); - } - - [Theory] - [InlineData("", "\"\"")] - [InlineData("\"", "\"\\\"\"")] - [InlineData("Hi", "\"Hi\"")] - [InlineData("This is a string", "\"This is a string\"")] - [InlineData("\"A quote\"", "\"\\\"A quote\\\"\"")] - [InlineData("This string has \"quotes\"", "\"This string has \\\"quotes\\\"\"")] - [InlineData("This string has \n newline", "\"This string has \\n newline\"")] - [InlineData("This string has \r also newline", "\"This string has \\r also newline\"")] - [InlineData("This string has \\ backslashes", "\"This string has \\\\ backslashes\"")] - [InlineData("This \"string\" has \n all \r kinds of \\ stuff", "\"This \\\"string\\\" has \\n all \\r kinds of \\\\ stuff\"")] - [InlineData("Some cool characters: { } = () %$! ß? ´'`@", "\"Some cool characters: { } = () %$! ß? ´'`@\"")] - public void TestToStringWithGMS2(string content, string expected) - { - var s = new UndertaleString(content); - var result = s.ToString(true); - Assert.Equal(expected, result); - } - - [Theory] - [InlineData("", "\"\"")] - [InlineData("\"", "'\"'")] - [InlineData("\"This starts with quotes", "'\"' + \"This starts with quotes\"")] - [InlineData("This ends with quotes\"", "\"This ends with quotes\" + '\"'")] - [InlineData("\"This has quotes in start and end\"", "'\"' + \"This has quotes in start and end\" + '\"'")] - [InlineData("This has quotes \" in middle", "\"This has quotes \" + '\"' + \" in middle\"")] - [InlineData("\"This starts and has \" quotes in middle", "'\"' + \"This starts and has \" + '\"' + \" quotes in middle\"")] - [InlineData("This ends and has \" quotes in middle\"", "\"This ends and has \" + '\"' + \" quotes in middle\" + '\"'")] - [InlineData("\"This starts, has \" quotes in middle and ends\"", "'\"' + \"This starts, has \" + '\"' + \" quotes in middle and ends\" + '\"'")] - [InlineData("Hi", "\"Hi\"")] - [InlineData("This is a string", "\"This is a string\"")] - [InlineData("This string has \n newline", "\"This string has \n newline\"")] - [InlineData("This \"string\" has \n all \r kinds of \\ stuff", "\"This \" + '\"' + \"string\" + '\"' + \" has \n all \r kinds of \\ stuff\"")] - [InlineData("Some cool characters: { } = () %$! ß? ´'`@", "\"Some cool characters: { } = () %$! ß? ´'`@\"")] - public void TestToStringWithGMS1(string content, string expected) - { - var s = new UndertaleString(content); - var result = s.ToString(false); - Assert.Equal(expected, result); - } -} \ No newline at end of file diff --git a/UndertaleModLibTests/UndertaleModLibTests.csproj b/UndertaleModLibTests/UndertaleModLibTests.csproj deleted file mode 100644 index 0c9589e08..000000000 --- a/UndertaleModLibTests/UndertaleModLibTests.csproj +++ /dev/null @@ -1,28 +0,0 @@ - - - - net8.0 - enable - enable - - false - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - - diff --git a/UndertaleModTests/GamePaths.cs b/UndertaleModTests/GamePaths.cs deleted file mode 100644 index 4335170c8..000000000 --- a/UndertaleModTests/GamePaths.cs +++ /dev/null @@ -1,61 +0,0 @@ -using Microsoft.VisualStudio.TestTools.UnitTesting; -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Security.Cryptography; -using System.Text; -using System.Threading.Tasks; -using UndertaleModLib; - -namespace UndertaleModTests -{ - internal static class GamePaths - { - public static string UNDERTALE_PATH = @"C:\Program Files (x86)\Steam\steamapps\common\Undertale\data.win"; - public static string UNDERTALE_MD5 = "5903fc5cb042a728d4ad8ee9e949c6eb"; - public static string UNDERTALE_SWITCH_PATH = @"..\..\..\Test\bin\Debug\switch\game.win"; - public static string UNDERTALE_SWITCH_MD5 = "427520a97db28c87da4220abb3a334c1"; - public static string DELTARUNE_PATH = @"C:\Program Files (x86)\SURVEY_PROGRAM\data.win"; - public static string DELTARUNE_MD5 = "a88a2db3a68c714ca2b1ff57ac08a032"; - } - - public abstract class GameTestBase - { - protected readonly string path; - protected readonly string expectedMD5; - protected UndertaleData data; - - protected static string GenerateMD5(Stream stream) - { - using (var md5 = MD5.Create()) - { - var hash = md5.ComputeHash(stream); - return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); - } - } - - public GameTestBase(string path, string md5) - { - this.path = path; - this.expectedMD5 = md5; - } - - [TestInitialize] - public void LoadData() - { - if (!File.Exists(path)) - Assert.Inconclusive("Unable to test, file not found: " + path); - - using (FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read)) - { - string fileMD5 = GenerateMD5(fs); - if (fileMD5 != expectedMD5) - Assert.Inconclusive("Unable to test, incorrect file: got " + fileMD5 + " expected " + expectedMD5); - fs.Position = 0; - - data = UndertaleIO.Read(fs); - } - } - } -} diff --git a/UndertaleModTests/UndertaleModTests.csproj b/UndertaleModTests/UndertaleModTests.csproj deleted file mode 100644 index 8e6478c6f..000000000 --- a/UndertaleModTests/UndertaleModTests.csproj +++ /dev/null @@ -1,21 +0,0 @@ - - - net8.0 - Library - false - AnyCPU;x64 - - - - - - - 4.11.0 - - - 3.5.2 - - - - - diff --git a/UndertaleModTool.sln b/UndertaleModTool.sln index 9e4d20a9b..83c2f3d66 100644 --- a/UndertaleModTool.sln +++ b/UndertaleModTool.sln @@ -7,13 +7,11 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UndertaleModTool", "Underta EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UndertaleModLib", "UndertaleModLib\UndertaleModLib.csproj", "{4781ADAC-9469-42C4-B357-4A0A157D7FCD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UndertaleModTests", "UndertaleModTests\UndertaleModTests.csproj", "{0B51CE42-C047-4B07-A8C9-88F4E3EA6DBD}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UndertaleModCli", "UndertaleModCli\UndertaleModCli.csproj", "{CC5FDC60-A955-4D0C-B59F-8BD451778237}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UndertaleModToolUpdater", "UndertaleModToolUpdater\UndertaleModToolUpdater.csproj", "{1E004B65-F3C8-4A62-B649-1465EA6A3B01}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UndertaleModToolUpdater", "UndertaleModToolUpdater\UndertaleModToolUpdater.csproj", "{1E004B65-F3C8-4A62-B649-1465EA6A3B01}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UndertaleModLibTests", "UndertaleModLibTests\UndertaleModLibTests.csproj", "{AAE3D4CA-0B6C-4928-AE86-066F5251F70A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "UndertaleModLib.Tests", "UndertaleModLib.Tests\UndertaleModLib.Tests.csproj", "{84864F47-9788-415D-A51D-791BE2B6339B}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -39,14 +37,6 @@ Global {4781ADAC-9469-42C4-B357-4A0A157D7FCD}.Release|Any CPU.Build.0 = Release|Any CPU {4781ADAC-9469-42C4-B357-4A0A157D7FCD}.Release|x64.ActiveCfg = Release|x64 {4781ADAC-9469-42C4-B357-4A0A157D7FCD}.Release|x64.Build.0 = Release|x64 - {0B51CE42-C047-4B07-A8C9-88F4E3EA6DBD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {0B51CE42-C047-4B07-A8C9-88F4E3EA6DBD}.Debug|Any CPU.Build.0 = Debug|Any CPU - {0B51CE42-C047-4B07-A8C9-88F4E3EA6DBD}.Debug|x64.ActiveCfg = Debug|x64 - {0B51CE42-C047-4B07-A8C9-88F4E3EA6DBD}.Debug|x64.Build.0 = Debug|x64 - {0B51CE42-C047-4B07-A8C9-88F4E3EA6DBD}.Release|Any CPU.ActiveCfg = Release|Any CPU - {0B51CE42-C047-4B07-A8C9-88F4E3EA6DBD}.Release|Any CPU.Build.0 = Release|Any CPU - {0B51CE42-C047-4B07-A8C9-88F4E3EA6DBD}.Release|x64.ActiveCfg = Release|x64 - {0B51CE42-C047-4B07-A8C9-88F4E3EA6DBD}.Release|x64.Build.0 = Release|x64 {CC5FDC60-A955-4D0C-B59F-8BD451778237}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {CC5FDC60-A955-4D0C-B59F-8BD451778237}.Debug|Any CPU.Build.0 = Debug|Any CPU {CC5FDC60-A955-4D0C-B59F-8BD451778237}.Debug|x64.ActiveCfg = Debug|x64 @@ -63,14 +53,14 @@ Global {1E004B65-F3C8-4A62-B649-1465EA6A3B01}.Release|Any CPU.Build.0 = Release|Any CPU {1E004B65-F3C8-4A62-B649-1465EA6A3B01}.Release|x64.ActiveCfg = Release|Any CPU {1E004B65-F3C8-4A62-B649-1465EA6A3B01}.Release|x64.Build.0 = Release|Any CPU - {AAE3D4CA-0B6C-4928-AE86-066F5251F70A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {AAE3D4CA-0B6C-4928-AE86-066F5251F70A}.Debug|Any CPU.Build.0 = Debug|Any CPU - {AAE3D4CA-0B6C-4928-AE86-066F5251F70A}.Debug|x64.ActiveCfg = Debug|Any CPU - {AAE3D4CA-0B6C-4928-AE86-066F5251F70A}.Debug|x64.Build.0 = Debug|Any CPU - {AAE3D4CA-0B6C-4928-AE86-066F5251F70A}.Release|Any CPU.ActiveCfg = Release|Any CPU - {AAE3D4CA-0B6C-4928-AE86-066F5251F70A}.Release|Any CPU.Build.0 = Release|Any CPU - {AAE3D4CA-0B6C-4928-AE86-066F5251F70A}.Release|x64.ActiveCfg = Release|Any CPU - {AAE3D4CA-0B6C-4928-AE86-066F5251F70A}.Release|x64.Build.0 = Release|Any CPU + {84864F47-9788-415D-A51D-791BE2B6339B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {84864F47-9788-415D-A51D-791BE2B6339B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {84864F47-9788-415D-A51D-791BE2B6339B}.Debug|x64.ActiveCfg = Debug|Any CPU + {84864F47-9788-415D-A51D-791BE2B6339B}.Debug|x64.Build.0 = Debug|Any CPU + {84864F47-9788-415D-A51D-791BE2B6339B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {84864F47-9788-415D-A51D-791BE2B6339B}.Release|Any CPU.Build.0 = Release|Any CPU + {84864F47-9788-415D-A51D-791BE2B6339B}.Release|x64.ActiveCfg = Release|Any CPU + {84864F47-9788-415D-A51D-791BE2B6339B}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE