From 1f298a4857ab7f522ca627e19a8bbb32757858ba Mon Sep 17 00:00:00 2001 From: Eusth Date: Fri, 17 Feb 2017 22:20:24 +0100 Subject: [PATCH] Add tests + more intelligent native DLL handling. --- IPA.Tests/IPA.Tests.csproj | 93 ++++++++++++++++++++++++++++ IPA.Tests/ProgramTest.cs | 39 ++++++++++++ IPA.Tests/Properties/AssemblyInfo.cs | 36 +++++++++++ IPA.Tests/ShortcutTest.cs | 37 +++++++++++ IPA.Tests/packages.config | 11 ++++ IPA.sln | 8 ++- IPA/Program.cs | 70 ++++++++++++++++++--- 7 files changed, 283 insertions(+), 11 deletions(-) create mode 100644 IPA.Tests/IPA.Tests.csproj create mode 100644 IPA.Tests/ProgramTest.cs create mode 100644 IPA.Tests/Properties/AssemblyInfo.cs create mode 100644 IPA.Tests/ShortcutTest.cs create mode 100644 IPA.Tests/packages.config diff --git a/IPA.Tests/IPA.Tests.csproj b/IPA.Tests/IPA.Tests.csproj new file mode 100644 index 0000000..f437fab --- /dev/null +++ b/IPA.Tests/IPA.Tests.csproj @@ -0,0 +1,93 @@ + + + + + + Debug + AnyCPU + {C66092B0-5C1E-44E9-B524-E0E8E1425379} + Library + Properties + IPA.Tests + IPA.Tests + v4.5.2 + 512 + + + + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll + True + + + ..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll + True + + + ..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll + True + + + ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll + True + + + + + + + + + + + + + {14092533-98bb-40a4-9afc-27bb75672a70} + IPA + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + \ No newline at end of file diff --git a/IPA.Tests/ProgramTest.cs b/IPA.Tests/ProgramTest.cs new file mode 100644 index 0000000..1d78af8 --- /dev/null +++ b/IPA.Tests/ProgramTest.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace IPA.Tests +{ + public class ProgramTest + { + [Theory] + // Unrelated path + [InlineData("test/from.dll", "test/to.dll", "native", false, new string[] { "test/to.dll" })] + + // Flat -> Not-Flat + [InlineData("native/from.dll", "native/to.dll", "native", false, new string[] { "native/x86/to.dll", "native/x86_64/to.dll" })] + + // Flat -> Flat + [InlineData("native/from.dll", "native/to.dll", "native", true, new string[] { "native/to.dll" })] + + // Not-Flat -> Flat + [InlineData("native/x86/from.dll", "native/x86/to.dll", "native", true, new string[] { })] + [InlineData("native/x86_64/from.dll", "native/x86_64/to.dll", "native", true, new string[] { "native/to.dll" })] + + // Not-flat -> Not-Flat + [InlineData("native/x86/from.dll", "native/x86/to.dll", "native", false, new string[] { "native/x86/to.dll" })] + [InlineData("native/x86_64/from.dll", "native/x86_64/to.dll", "native", false, new string[] { "native/x86_64/to.dll" })] + + public void CopiesCorrectly(string from, string to, string nativeFolder, bool isFlat, string[] expected) + { + var outcome = Program.NativePluginInterceptor(new FileInfo(from), new FileInfo(to), new DirectoryInfo(nativeFolder), isFlat).Select(f => f.FullName).ToList(); + + var expectedPaths = expected.Select(e => new FileInfo(e)).Select(f => f.FullName).ToList(); + Assert.Equal(expectedPaths, outcome); + } + } +} diff --git a/IPA.Tests/Properties/AssemblyInfo.cs b/IPA.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..07343ad --- /dev/null +++ b/IPA.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("IPA.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("IPA.Tests")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c66092b0-5c1e-44e9-b524-e0e8e1425379")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/IPA.Tests/ShortcutTest.cs b/IPA.Tests/ShortcutTest.cs new file mode 100644 index 0000000..3229153 --- /dev/null +++ b/IPA.Tests/ShortcutTest.cs @@ -0,0 +1,37 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Xunit; + +namespace IPA.Tests +{ + public class ShortcutTest + { + [Fact] + public void CanDealWithEmptyFiles() + { + Shortcut.Create(".lnk", "", "", "", "", "", ""); + } + + [Fact] + public void CanDealWithLongFiles() + { + Shortcut.Create(".lnk", Path.Combine(Path.GetTempPath(), string.Join("_", new string[500])), "", "", "", "", ""); + } + + [Fact] + public void CantDealWithNull() + { + Assert.Throws(() => Shortcut.Create(".lnk", null, "", "", "", "", "")); + } + + [Fact] + public void CanDealWithWeirdCharacters() + { + Shortcut.Create(".lnk", "äöü", "", "", "", "", ""); + } + } +} diff --git a/IPA.Tests/packages.config b/IPA.Tests/packages.config new file mode 100644 index 0000000..30b6958 --- /dev/null +++ b/IPA.Tests/packages.config @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/IPA.sln b/IPA.sln index edd3f93..32a6edf 100644 --- a/IPA.sln +++ b/IPA.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 14 -VisualStudioVersion = 14.0.25123.0 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA", "IPA\IPA.csproj", "{14092533-98BB-40A4-9AFC-27BB75672A70}" ProjectSection(ProjectDependencies) = postProject @@ -16,6 +16,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IllusionPlugin", "IllusionP EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IllusionInjector", "IllusionInjector\IllusionInjector.csproj", "{D1C61AF5-0D2D-4752-8203-1C6929025F7C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "IPA.Tests", "IPA.Tests\IPA.Tests.csproj", "{C66092B0-5C1E-44E9-B524-E0E8E1425379}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,6 +40,10 @@ Global {D1C61AF5-0D2D-4752-8203-1C6929025F7C}.Debug|Any CPU.Build.0 = Debug|Any CPU {D1C61AF5-0D2D-4752-8203-1C6929025F7C}.Release|Any CPU.ActiveCfg = Release|Any CPU {D1C61AF5-0D2D-4752-8203-1C6929025F7C}.Release|Any CPU.Build.0 = Release|Any CPU + {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C66092B0-5C1E-44E9-B524-E0E8E1425379}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/IPA/Program.cs b/IPA/Program.cs index ea392e3..4da0f66 100644 --- a/IPA/Program.cs +++ b/IPA/Program.cs @@ -13,7 +13,7 @@ using System.Windows.Forms; namespace IPA { - class Program + public class Program { static void Main(string[] args) @@ -59,8 +59,11 @@ namespace IPA try { // Copying - Console.Write("Updating files... "); - CopyAll(new DirectoryInfo(context.DataPathSrc), new DirectoryInfo(context.DataPathDst)); + Console.WriteLine("Updating files... "); + var nativePluginFolder = Path.Combine(context.DataPathDst, "Plugins"); + bool isFlat = Directory.Exists(nativePluginFolder) && Directory.GetFiles(nativePluginFolder).Any(f => f.EndsWith(".dll")); + CopyAll(new DirectoryInfo(context.DataPathSrc), new DirectoryInfo(context.DataPathDst), (from, to) => NativePluginInterceptor(from, to, new DirectoryInfo(nativePluginFolder), isFlat) ); + Console.WriteLine("Successfully updated files!"); if (!Directory.Exists(context.PluginsFolder)) @@ -165,18 +168,65 @@ namespace IPA } } - public static void CopyAll(DirectoryInfo source, DirectoryInfo target) + public static IEnumerable NativePluginInterceptor(FileInfo from, FileInfo to, DirectoryInfo nativePluginFolder, bool isFlat) + { + if (to.FullName.StartsWith(nativePluginFolder.FullName)) + { + var relevantBit = to.FullName.Substring(nativePluginFolder.FullName.Length + 1); + // Goes into the plugin folder! + bool isFileFlat = !relevantBit.StartsWith("x86"); + if (isFlat && !isFileFlat) + { + // Flatten structure + if (relevantBit.StartsWith("x86_64")) + { + yield return new FileInfo(Path.Combine(nativePluginFolder.FullName, relevantBit.Substring("x86_64".Length + 1))); + } + else + { + // Throw away + yield break; + } + } + else if (!isFlat && isFileFlat) + { + // Deepen structure + yield return new FileInfo(Path.Combine(Path.Combine(nativePluginFolder.FullName, "x86"), relevantBit)); + yield return new FileInfo(Path.Combine(Path.Combine(nativePluginFolder.FullName, "x86_64"), relevantBit)); + } + else + { + yield return to; + } + } + else + { + yield return to; + } + } + private static IEnumerable PassThroughInterceptor(FileInfo from, FileInfo to) + { + yield return to; + } + + public static void CopyAll(DirectoryInfo source, DirectoryInfo target, Func> interceptor = null) { + if(interceptor == null) + { + interceptor = PassThroughInterceptor; + } + Directory.CreateDirectory(target.FullName); // Copy each file into the new directory. foreach (FileInfo fi in source.GetFiles()) { - string targetFile = Path.Combine(target.FullName, fi.Name); - if (!File.Exists(targetFile) || File.GetLastWriteTimeUtc(targetFile) < fi.LastWriteTimeUtc) - { - Console.WriteLine(@"Copying {0}\{1}", target.FullName, fi.Name); - fi.CopyTo(Path.Combine(target.FullName, fi.Name), true); + foreach(var targetFile in interceptor(fi, new FileInfo(Path.Combine(target.FullName, fi.Name)))) { + if (!targetFile.Exists || targetFile.LastWriteTimeUtc < fi.LastWriteTimeUtc) + { + Console.WriteLine(@"Copying {0}", targetFile.FullName); + fi.CopyTo(targetFile.FullName, true); + } } } @@ -185,7 +235,7 @@ namespace IPA { DirectoryInfo nextTargetSubDir = target.CreateSubdirectory(diSourceSubDir.Name); - CopyAll(diSourceSubDir, nextTargetSubDir); + CopyAll(diSourceSubDir, nextTargetSubDir, interceptor); } }