예제 #1
0
        private void runTest(string testPath)
        {
            // Android
            var testFile = testPath + @"\" + Path.GetFileName(testPath) + ".so";

            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\libil2cpp.so";
            }
            // Windows
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath) + ".dll";
            }
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\GameAssembly.dll";
            }
            // iOS
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath);
            }

            var inspectors = Il2CppInspector.LoadFromFile(testFile, testPath + @"\global-metadata.dat");

            // If null here, there was a problem parsing the files
            if (inspectors == null)
            {
                throw new Exception("Could not understand IL2CPP binary or metadata");
            }

            if (inspectors.Count == 0)
            {
                throw new Exception("Could not find any images in the IL2CPP binary");
            }

            // Dump each image in the binary separately
            int i = 0;

            foreach (var il2cpp in inspectors)
            {
                var model      = new TypeModel(il2cpp);
                var appModel   = new AppModel(model, makeDefaultBuild: false).Build(compiler: CppCompilerType.MSVC);
                var nameSuffix = i++ > 0 ? "-" + (i - 1) : "";

                new CSharpCodeStubs(model)
                {
                    ExcludedNamespaces = Constants.DefaultExcludedNamespaces,
                    SuppressMetadata   = false,
                    MustCompile        = true
                }.WriteSingleFile(testPath + $@"\test-result{nameSuffix}.cs");

                new JSONMetadata(appModel)
                .Write(testPath + $@"\test-result{nameSuffix}.json");

                new CppScaffolding(appModel)
                .Write(testPath + $@"\test-cpp-result{nameSuffix}");

                var python = new PythonScript(appModel);
                foreach (var target in PythonScript.GetAvailableTargets())
                {
                    python.WriteScriptToFile(testPath + $@"\test-{target.ToLower()}{nameSuffix}.py", target,
                                             testPath + $@"\test-cpp-result{nameSuffix}\appdata\il2cpp-types.h",
                                             testPath + $@"\test-result{nameSuffix}.json");
                }
            }

            // Compare test results with expected results
            for (i = 0; i < inspectors.Count; i++)
            {
                var suffix = (i > 0 ? "-" + i : "");

                compareFiles(testPath, suffix + ".cs", $"test-result{suffix}.cs");
                compareFiles(testPath, suffix + ".json", $"test-result{suffix}.json");
                compareFiles(testPath, suffix + ".h", $@"test-cpp-result{suffix}\appdata\il2cpp-types.h");
            }
        }
예제 #2
0
        // Test runner
        private async Task runTest(string testPath, LoadOptions loadOptions = null)
        {
            // Android
            var testFile = testPath + @"\" + Path.GetFileName(testPath) + ".so";

            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\libil2cpp.so";
            }
            // Windows
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath) + ".dll";
            }
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\GameAssembly.dll";
            }
            // iOS
            if (!File.Exists(testFile))
            {
                testFile = testPath + @"\" + Path.GetFileName(testPath);
            }
            // Linux process map
            if (!File.Exists(testFile))
            {
                testFile = Directory.GetFiles(testPath, "*-maps.txt").FirstOrDefault();
            }
            // XAPK (selects latest version assuming lexical order)
            if (testFile == null)
            {
                testFile = Directory.GetFiles(testPath, "*.xapk").LastOrDefault();
            }
            // APK (selects latest version assuming lexical order) (prefer XAPKs)
            if (testFile == null)
            {
                testFile = Directory.GetFiles(testPath, "*.apk").LastOrDefault();
            }

            // Set load options
            if (loadOptions == null)
            {
                loadOptions = new LoadOptions();
            }

            loadOptions.BinaryFilePath = testFile;

            // Load core plugins
            PluginManager.Reload(testPath + @"\..\plugins", coreOnly: true);

            // Set up additional plugins - place desired plugins in 'plugins' sub-folder of test folder
            try {
                PluginManager.Reload(testPath + @"\plugins", reset: false);
            } catch (DirectoryNotFoundException) { }

            // Handlers for debugging output
            PluginManager.StatusHandler += (s, e) => {
                Console.WriteLine("Plugin " + e.Plugin.Name + ": " + e.Text);
            };

            PluginManager.ErrorHandler += (s, e) => {
                Assert.Fail($"{e.Error.Plugin.Name} throw an exception during {e.Error.Operation}: {e.Error.Exception.Message}.", e);
            };

            // Get plugin options - place desired options in <plugins-id>.options.txt for each plugin in test folder
            // in the format "key=value", one per line
            // Use %TESTDIR% to refer to the directory containing the test files
            foreach (var plugin in PluginManager.AvailablePlugins)
            {
                Console.WriteLine("Using plugin: " + plugin.Name);

                // Enable plugin
                var ourPlugin = PluginManager.Plugins[plugin.Id];
                ourPlugin.Enabled = true;

                // Look for options
                var optionsFile = $@"{testPath}\{plugin.Id}-options.txt";
                if (File.Exists(optionsFile))
                {
                    var options = File.ReadAllLines(optionsFile);

                    // Parse options
                    foreach (var option in options)
                    {
                        var kv = option.Split('=', 2);
                        if (kv.Length == 2)
                        {
                            var key   = kv[0].Trim();
                            var value = kv[1].Trim().Replace("%TESTDIR%", testPath);

                            Console.WriteLine($"Setting option: {key} = {value}");

                            // Null default values must be castable to object
                            ourPlugin.Plugin.Options.Single(o => o.Name == key).SetFromString(value);
                        }
                    }
                }
                PluginManager.OptionsChanged(plugin);
            }

            List <Il2CppInspector> inspectors;

            using (new Benchmark("Load IL2CPP metadata and binary"))
                try {
                    inspectors = Il2CppInspector.LoadFromFile(testFile, testPath + @"\global-metadata.dat", loadOptions);
                } catch (FileNotFoundException) {
                    inspectors = Il2CppInspector.LoadFromPackage(new[] { testFile }, loadOptions);
                }

            // If null here, there was a problem parsing the files
            if (inspectors == null)
            {
                throw new Exception("Could not understand IL2CPP binary or metadata");
            }

            if (inspectors.Count == 0)
            {
                throw new Exception("Could not find any images in the IL2CPP binary");
            }

            // End if we were only testing file load
            if (!GenerateCpp && !GenerateCS && !GenerateDLL && !GenerateJSON && !GeneratePython)
            {
                return;
            }

            // Dump each image in the binary separately
            var imageTasks = inspectors.Select((il2cpp, i) => Task.Run(async() =>
            {
                TypeModel model;
                using (new Benchmark("Create .NET type model"))
                    model = new TypeModel(il2cpp);

                Task <AppModel> appModelTask = null;
                if (GenerateCpp || GenerateJSON || GeneratePython)
                {
                    appModelTask = Task.Run(() => {
                        using (new Benchmark("Create application model"))
                            return(new AppModel(model, makeDefaultBuild: false).Build(compiler: CppCompilerType.MSVC));
                    });
                }

                var nameSuffix    = i++ > 0 ? "-" + (i - 1) : "";
                var generateTasks = new List <Task>();
                var compareTasks  = new List <Task>();

                if (GenerateCS)
                {
                    generateTasks.Add(Task.Run(() => {
                        using (new Benchmark("Create C# code stubs"))
                            new CSharpCodeStubs(model)
                            {
                                ExcludedNamespaces = Constants.DefaultExcludedNamespaces,
                                SuppressMetadata   = false,
                                MustCompile        = true
                            }.WriteSingleFile(testPath + $@"\test-result{nameSuffix}.cs");

                        compareTasks.Add(Task.Run(() => compareFiles(testPath, nameSuffix + ".cs", $"test-result{nameSuffix}.cs")));
                    }));
                }

                if (GenerateDLL)
                {
                    generateTasks.Add(Task.Run(() => {
                        using (new Benchmark("Create .NET assembly shims"))
                            new AssemblyShims(model).Write(testPath + $@"\test-dll-result{nameSuffix}");

                        compareTasks.Add(Task.Run(() => compareBinaryFiles(testPath + $@"\test-dll-result{nameSuffix}",
                                                                           testPath + @"\..\..\TestExpectedResults\dll-" + Path.GetFileName(testPath) + nameSuffix)));
                    }));
                }

                AppModel appModel = null;
                if (appModelTask != null)
                {
                    appModel = await appModelTask;
                }

                if (GenerateJSON || GeneratePython)
                {
                    generateTasks.Add(Task.Run(() => {
                        using (new Benchmark("Create JSON metadata"))
                            new JSONMetadata(appModel)
                            .Write(testPath + $@"\test-result{nameSuffix}.json");

                        compareTasks.Add(Task.Run(() => compareFiles(testPath, nameSuffix + ".json", $"test-result{nameSuffix}.json")));
                    }));
                }

                if (GenerateCpp || GeneratePython)
                {
                    generateTasks.Add(Task.Run(() => {
                        using (new Benchmark("Create C++ scaffolding"))
                            new CppScaffolding(appModel)
                            .Write(testPath + $@"\test-cpp-result{nameSuffix}");

                        compareTasks.Add(Task.Run(() => compareFiles(testPath, nameSuffix + ".h", $@"test-cpp-result{nameSuffix}\appdata\il2cpp-types.h")));
                    }));
                }

                if (GeneratePython)
                {
                    generateTasks.Add(Task.Run(() => {
                        var python = new PythonScript(appModel);
                        foreach (var target in PythonScript.GetAvailableTargets())
                        {
                            python.WriteScriptToFile(testPath + $@"\test-{target.ToLower()}{nameSuffix}.py", target,
                                                     testPath + $@"\test-cpp-result{nameSuffix}\appdata\il2cpp-types.h",
                                                     testPath + $@"\test-result{nameSuffix}.json");
                        }
                    }));
                }

                await Task.WhenAll(generateTasks);
                await Task.WhenAll(compareTasks);
            }));
            await Task.WhenAll(imageTasks);
        }