static string Execute(string workingDirectory, string executable, PlatformName platform)
        {
            switch (platform)
            {
            case PlatformName.macOS: {
                // for macOS we create an app bundle with mmp
                var name = Path.GetFileNameWithoutExtension(executable);
                var mmp  = new StringBuilder();

                mmp.AppendLine($"/cache:{StringUtils.Quote (Path.Combine (workingDirectory, "mmp-cache"))}");
                mmp.AppendLine($"/root-assembly:{StringUtils.Quote (Path.Combine (workingDirectory, executable))}");
                mmp.AppendLine($"/sdkroot:/Applications/Xcode.app");
                mmp.AppendLine($"/profile:Xamarin.Mac,v2.0,Profile=Mobile");
                mmp.AppendLine($"/arch:x86_64");
                mmp.AppendLine($"/assembly:{StringUtils.Quote (Path.Combine (ConstructorTests.kXamarinMacDir, "Xamarin.Mac.dll"))}");
                mmp.AppendLine($"/output:{StringUtils.Quote (Path.Combine (workingDirectory, name))}");
                mmp.AppendLine($"/assembly:{StringUtils.Quote (Path.Combine (ConstructorTests.kSwiftRuntimeMacOutputDirectory, ConstructorTests.kSwiftRuntimeLibraryMac))}.dll");
                mmp.AppendLine($"/debug");
                mmp.AppendLine($"/linksdkonly");                                                                // FIXME: link all doesn't work for all tests, this needs looking into.
                mmp.AppendLine($"/native-reference:{StringUtils.Quote (Compiler.kSwiftRuntimeGlueDirectory)}"); // link with XamGlue.framework
                foreach (var dylib in Directory.GetFiles(workingDirectory, "*.dylib"))                          // Link with any dylibs produced by the test
                {
                    mmp.AppendLine($"/native-reference:{StringUtils.Quote (dylib)}");
                }
                mmp.AppendLine($"/v /v /v /v");

                var output       = new StringBuilder();
                var responseFile = Path.Combine(workingDirectory, name + ".rsp");
                File.WriteAllText(responseFile, mmp.ToString());
                var rv = ExecAndCollect.RunCommand("/Library/Frameworks/Xamarin.Mac.framework/Versions/Current/bin/mmp", "--link_flags=-headerpad_max_install_names " + StringUtils.Quote($"@{responseFile}"), output: output, verbose: true);
                if (rv != 0)
                {
                    Console.WriteLine(output);
                    throw new Exception($"Failed to run mmp, exit code: {rv}");
                }

                // This should probably go into mmp/mtouch
                // run swift-stdlib-tool to get swift libraries into the app.
                var appPath           = Path.Combine(workingDirectory, name, name + ".app");
                var appExecutable     = Path.Combine(appPath, "Contents", "MacOS", name);
                var swift_stdlib_tool = new StringBuilder();
                swift_stdlib_tool.Append($"swift-stdlib-tool ");
                swift_stdlib_tool.Append($"--copy ");
                swift_stdlib_tool.Append($"--verbose ");
                swift_stdlib_tool.Append($"--scan-executable {StringUtils.Quote (appExecutable)} ");
                swift_stdlib_tool.Append($"--platform macosx ");
                swift_stdlib_tool.Append($"--destination {StringUtils.Quote (Path.Combine (appPath, "Contents", "Frameworks"))} ");
                swift_stdlib_tool.Append($"--strip-bitcode ");
                swift_stdlib_tool.Append($"--scan-folder {StringUtils.Quote (Path.Combine (appPath, "Contents", "MonoBundle"))} ");
                swift_stdlib_tool.Append($"--scan-folder {StringUtils.Quote (Path.Combine (appPath, "Contents", "Frameworks"))} ");
                swift_stdlib_tool.Append($"--platform macosx ");
                swift_stdlib_tool.Append($"--source-libraries {StringUtils.Quote (Compiler.CompilerLocation.SwiftCompilerLib)} ");
                output.Clear();
                rv = ExecAndCollect.RunCommand("xcrun", swift_stdlib_tool.ToString(), output: output, verbose: true);
                if (rv != 0)
                {
                    Console.WriteLine(output);
                    throw new Exception($"Failed to run swift-stdlib-tool, exit code: {rv}\n{output}\n");
                }

                // This should probably go into mmp/mtouch
                // make sure the executable has the Frameworks and MonoBundle directories as rpaths.
                var install_name_tool = new StringBuilder();
                install_name_tool.Append($"install_name_tool ");
                install_name_tool.Append($"-add_rpath @executable_path/../Frameworks ");
                install_name_tool.Append($"-add_rpath @executable_path/../MonoBundle ");
                install_name_tool.Append($"{StringUtils.Quote (Path.Combine (appPath, "Contents", "MacOS", name))} ");
                output.Clear();
                rv = ExecAndCollect.RunCommand("xcrun", install_name_tool.ToString(), output: output, verbose: true);
                if (rv != 0)
                {
                    Console.WriteLine(output);
                    throw new Exception($"Failed to run install_name_tool, exit code: {rv}\n{output}\n");
                }

                var exec_output = new StringBuilder();
                var exec_env    = new Dictionary <string, string> ();
                //exec_env.Add ("MONO_LOG_LEVEL", "debug");
                //exec_env.Add ("MONO_LOG_MASK", "dll");
                var exec_rv = Compiler.RunCommandWithLeaks(appExecutable, new StringBuilder(), exec_env, exec_output);
                if (exec_rv != 0)
                {
                    Console.WriteLine(exec_output);
                    throw new Exception($"Execution failed with exit code {exec_rv}\n{output}\n{exec_output}");
                }
                return(exec_output.ToString());
            }

            case PlatformName.iOS:
                Assert.Ignore($"Execution does not apply during a test run for {platform}, tests will be executed as part of the device tests.");
                return(string.Empty);

            case PlatformName.None: {
                return(Compiler.RunWithMono(executable, workingDirectory, platform: platform));
            }

            default:
                throw new NotImplementedException(platform.ToString());
            }
        }
        public static void TestAndExecute(string swiftCode, CodeElementCollection <ICodeElement> callingCode,
                                          string expectedOutput,
                                          string testName                  = null,
                                          CSClass otherClass               = null, string skipReason = null,
                                          string iosExpectedOutput         = null,
                                          PlatformName platform            = PlatformName.None,
                                          UnicodeMapper unicodeMapper      = null, int expectedErrorCount = 0,
                                          Action <string> postCompileCheck = null,
                                          string[] expectedOutputContains  = null)
        {
            SetInvokingTestNameIfUnset(ref testName, out string nameSpace);
            string testClassName = "TomTest" + testName;

            using (var provider = new DisposableTempDirectory()) {
                var compiler = Utils.CompileSwift(swiftCode, provider, nameSpace);

                var libName           = $"lib{nameSpace}.dylib";
                var tempDirectoryPath = Path.Combine(provider.DirectoryPath, "BuildDir");
                Directory.CreateDirectory(tempDirectoryPath);
                File.Copy(Path.Combine(compiler.DirectoryPath, libName), Path.Combine(tempDirectoryPath, libName));

                Utils.CompileToCSharp(provider, tempDirectoryPath, nameSpace, unicodeMapper: unicodeMapper, expectedErrorCount: expectedErrorCount);
                if (postCompileCheck != null)
                {
                    postCompileCheck(tempDirectoryPath);
                }

                Tuple <CSNamespace, CSUsingPackages> testClassParts = TestRunningCodeGenerator.CreateTestClass(callingCode, testName, iosExpectedOutput ?? expectedOutput, nameSpace,
                                                                                                               testClassName, otherClass, skipReason, platform);

                var thisTestPath = Path.Combine(Compiler.kSwiftDeviceTestRoot, nameSpace);
                Directory.CreateDirectory(thisTestPath);

                var thisTestPathSwift = Path.Combine(thisTestPath, "swiftsrc");
                Directory.CreateDirectory(thisTestPathSwift);

                var swiftPrefix = string.Empty;
                var swiftSuffix = string.Empty;
                var csPrefix    = string.Empty;
                var csSuffix    = string.Empty;
                var nameSuffix  = string.Empty;
                switch (platform)
                {
                case PlatformName.macOS:
                    swiftPrefix = "#if os(OSX)\n";
                    swiftSuffix = "#endif\n";
                    csPrefix    = "#if __MACOS__\n";
                    csSuffix    = "\n#endif\n";
                    nameSuffix  = "_macOS";
                    break;

                case PlatformName.iOS:
                    swiftPrefix = "#if os(iOS)\n";
                    swiftSuffix = "#endif\n";
                    csPrefix    = "#if __IOS__\n";
                    csSuffix    = "\n#endif\n";
                    nameSuffix  = "_iOS";
                    break;

                case PlatformName.tvOS:
                    swiftPrefix = "#if os(tvOS)\n";
                    swiftSuffix = "#endif\n";
                    csPrefix    = "#if __TVOS__\n";
                    csSuffix    = "\n#endif\n";
                    nameSuffix  = "_tvOS";
                    break;

                case PlatformName.watchOS:
                    swiftPrefix = "#if os(watchOS)\n";
                    swiftSuffix = "#endif\n";
                    csPrefix    = "#if __WATCHOS__\n";
                    csSuffix    = "\n#endif\n";
                    nameSuffix  = "_watchOS";
                    break;

                case PlatformName.None:
                    break;

                default:
                    throw new NotImplementedException(platform.ToString());
                }

                File.WriteAllText(Path.Combine(thisTestPathSwift, $"{testClassName}{testName}{nameSuffix}.swift"), swiftPrefix + swiftCode + swiftSuffix);

                CSFile csTestFile     = CSFile.Create(testClassParts.Item2, testClassParts.Item1);
                var    csTestFilePath = Path.Combine(thisTestPath, $"{testClassName}{testName}{nameSuffix}.cs");
                // Write out the file without csPrefix/csSuffix
                CodeWriter.WriteToFile(csTestFilePath, csTestFile);
                if (!string.IsNullOrEmpty(csPrefix) || !string.IsNullOrEmpty(csSuffix))
                {
                    // Read the C# code, and prepend/append the csPrefix/csSuffix blobs, then save the modified contents again.
                    File.WriteAllText(csTestFilePath, csPrefix + File.ReadAllText(csTestFilePath) + csSuffix);
                }

                var csFile = TestRunningCodeGenerator.GenerateTestEntry(callingCode, testName, nameSpace, platform, otherClass);
                csFile.Namespaces.Add(CreateManagedConsoleRedirect());
                CodeWriter.WriteToFile(Path.Combine(tempDirectoryPath, "NameNotImportant.cs"), csFile);

                var sourceFiles     = Directory.GetFiles(tempDirectoryPath, "*.cs");
                var objcRuntimePath = Path.Combine(tempDirectoryPath, "ObjCRuntime");
                if (Directory.Exists(objcRuntimePath))
                {
                    sourceFiles = sourceFiles.And(Directory.GetFiles(objcRuntimePath, "*.cs"));
                }

                var compilerWarnings = Compiler.CSCompile(tempDirectoryPath, sourceFiles, "NameNotImportant.exe", platform: platform);

                if (compilerWarnings.Contains("warning"))
                {
                    FailOnBadWarnings(compilerWarnings);
                }

                CopyTestReferencesTo(tempDirectoryPath, platform);

                var output = Execute(tempDirectoryPath, "NameNotImportant.exe", platform);
                if (expectedOutput != null)
                {
                    Assert.AreEqual(expectedOutput, output);
                }
                else
                {
                    foreach (var s in expectedOutputContains)
                    {
                        Assert.IsTrue(output.Contains(s), $"Expected to find string {s} in {output}");
                    }
                }
            }
        }