diff --git a/appveyor.yml b/appveyor.yml index ce345cbf8..b960c6ace 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -75,6 +75,9 @@ on_finish: artifacts: - path: dist\* + - path: TestResult.xml + name: TestResult + type: xml notifications: - provider: Slack diff --git a/pythonnet.sln b/pythonnet.sln index d446d81d3..c5afd66c3 100644 --- a/pythonnet.sln +++ b/pythonnet.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28010.2046 +# Visual Studio 14 +VisualStudioVersion = 14.0.25420.1 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Python.Runtime", "src\runtime\Python.Runtime.csproj", "{097B4AC0-74E9-4C58-BCF8-C69746EC8271}" EndProject @@ -32,38 +32,38 @@ Global ReleaseWinPY3|x86 = ReleaseWinPY3|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x64.ActiveCfg = DebugMono|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x64.Build.0 = DebugMono|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x86.ActiveCfg = DebugMono|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x86.Build.0 = DebugMono|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x64.ActiveCfg = DebugWin|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x64.Build.0 = DebugWin|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x86.ActiveCfg = DebugWin|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x86.Build.0 = DebugWin|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x64.Build.0 = DebugWinPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x86.Build.0 = DebugWinPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x64.ActiveCfg = ReleaseMono|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x64.Build.0 = ReleaseMono|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x86.ActiveCfg = ReleaseMono|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x86.Build.0 = ReleaseMono|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x64.ActiveCfg = ReleaseWin|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x64.Build.0 = ReleaseWin|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x86.ActiveCfg = ReleaseWin|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x86.Build.0 = ReleaseWin|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|Any CPU - {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|Any CPU + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x64.ActiveCfg = DebugMono|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x64.Build.0 = DebugMono|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x86.ActiveCfg = DebugMono|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMono|x86.Build.0 = DebugMono|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x64.ActiveCfg = DebugMonoPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x64.Build.0 = DebugMonoPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x86.ActiveCfg = DebugMonoPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugMonoPY3|x86.Build.0 = DebugMonoPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x64.ActiveCfg = DebugWin|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x64.Build.0 = DebugWin|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x86.ActiveCfg = DebugWin|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWin|x86.Build.0 = DebugWin|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x64.ActiveCfg = DebugWinPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x64.Build.0 = DebugWinPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x86.ActiveCfg = DebugWinPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.DebugWinPY3|x86.Build.0 = DebugWinPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x64.ActiveCfg = ReleaseMono|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x64.Build.0 = ReleaseMono|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x86.ActiveCfg = ReleaseMono|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMono|x86.Build.0 = ReleaseMono|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x64.ActiveCfg = ReleaseMonoPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x64.Build.0 = ReleaseMonoPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x86.ActiveCfg = ReleaseMonoPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseMonoPY3|x86.Build.0 = ReleaseMonoPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x64.ActiveCfg = ReleaseWin|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x64.Build.0 = ReleaseWin|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x86.ActiveCfg = ReleaseWin|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWin|x86.Build.0 = ReleaseWin|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x64.ActiveCfg = ReleaseWinPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x64.Build.0 = ReleaseWinPY3|x64 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x86.ActiveCfg = ReleaseWinPY3|x86 + {097B4AC0-74E9-4C58-BCF8-C69746EC8271}.ReleaseWinPY3|x86.Build.0 = ReleaseWinPY3|x86 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x64.ActiveCfg = DebugMono|x64 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x64.Build.0 = DebugMono|x64 {6F401A34-273B-450F-9A4C-13550BE0767B}.DebugMono|x86.ActiveCfg = DebugMono|x86 @@ -188,9 +188,6 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection - GlobalSection(ExtensibilityGlobals) = postSolution - SolutionGuid = {10AE1870-1175-445A-B23A-C83497EAAE4B} - EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = src\console\Console.csproj Policies = $0 diff --git a/src/embed_tests/Python.EmbeddingTest.15.csproj b/src/embed_tests/Python.EmbeddingTest.15.csproj index a741a589e..b212cf461 100644 --- a/src/embed_tests/Python.EmbeddingTest.15.csproj +++ b/src/embed_tests/Python.EmbeddingTest.15.csproj @@ -1,4 +1,4 @@ - + @@ -82,8 +82,12 @@ + + + 4.5.0 + diff --git a/src/embed_tests/Python.EmbeddingTest.csproj b/src/embed_tests/Python.EmbeddingTest.csproj index 6aa48becc..da32f7f3d 100644 --- a/src/embed_tests/Python.EmbeddingTest.csproj +++ b/src/embed_tests/Python.EmbeddingTest.csproj @@ -80,6 +80,7 @@ + diff --git a/src/embed_tests/TestConsoleInterrupt.cs b/src/embed_tests/TestConsoleInterrupt.cs new file mode 100644 index 000000000..a6e8b4d58 --- /dev/null +++ b/src/embed_tests/TestConsoleInterrupt.cs @@ -0,0 +1,127 @@ +using Microsoft.CSharp; +using NUnit.Framework; +using Python.Runtime; +using System; +using System.CodeDom.Compiler; +using System.Diagnostics; +using System.Runtime.InteropServices; +using System.Text; + +namespace Python.EmbeddingTest +{ + /// + /// This class tests that a console application with PythonEngine Initialize can be interrupted by CTRL+C. + /// + public class TestConsoleInterrupt + { + static readonly string program = @" + using System; + using Python.Runtime; + using System.Text; + using System.Diagnostics; + class Program + { + static void Main(string[] args) + { + PythonEngine.Initialize(); // Comment this out to support CTRL+C again. + Console.WriteLine(""Waiting 5s.. Try CTRL+C.""); + System.Threading.Thread.Sleep(5000); + Console.WriteLine(""Timeout""); + } + } + "; + + static string BuildAssembly(string code) + { + var provider = new CSharpCodeProvider(); + var compilerparams = new CompilerParameters(); + compilerparams.GenerateExecutable = true; + compilerparams.GenerateInMemory = false; + if (IntPtr.Size == 8) + { + compilerparams.CompilerOptions = "/platform:x64"; + } + else + { + compilerparams.CompilerOptions = "/platform:x86"; + } + + var dir = TestContext.CurrentContext.TestDirectory; + + compilerparams.OutputAssembly = System.IO.Path.Combine(dir, "testctrl.exe"); + compilerparams.ReferencedAssemblies.Add(typeof(PythonEngine).Assembly.Location); + CompilerResults results = provider.CompileAssemblyFromSource(compilerparams, code); + if (results.Errors.HasErrors) + { + StringBuilder errors = new StringBuilder("Compiler Errors :\r\n"); + foreach (CompilerError error in results.Errors) + { + errors.AppendFormat("Line {0},{1}\t: {2}\n", error.Line, error.Column, error.ErrorText); + } + throw new Exception(errors.ToString()); + } + else + { + return results.PathToAssembly; + } + } + +#if MONO_LINUX || MONO_OSX + [DllImport("libc")] + static extern bool kill(int pid, int signal); + + static void invokeSigInt(Process proc) + { + int SIGINT = 2; + kill(proc.Id, SIGINT); + } + +#else + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool GenerateConsoleCtrlEvent(int sigevent, int dwProcessGroupId); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool AttachConsole(uint dwProcessId); + + [DllImport("kernel32.dll", SetLastError = true, ExactSpelling = true)] + static extern bool FreeConsole(); + + [DllImport("kernel32.dll")] + static extern bool SetConsoleCtrlHandler(int handler, bool add); + + static void invokeSigInt(Process proc) + { + FreeConsole(); + AttachConsole((uint)proc.Id); + SetConsoleCtrlHandler(0, true); + System.Threading.Thread.Sleep(50); + GenerateConsoleCtrlEvent(0, 0); + System.Threading.Thread.Sleep(50); + FreeConsole(); + SetConsoleCtrlHandler(0, false); + } + +#endif + + [Test] + public static void ConsoleInterrupt() + { + var path = BuildAssembly(program); + using (var process = Process.Start(new ProcessStartInfo(path, "") { UseShellExecute = false, RedirectStandardOutput = true })) + { + + System.Threading.Thread.Sleep(100); + invokeSigInt(process); + if (!process.WaitForExit(500)) + { + process.Kill(); + Assert.Fail(); + } + var str = process.StandardOutput.ReadToEnd(); + Assert.IsTrue(str.Contains("Waiting")); // Program starts with "Waiting". + Assert.IsTrue(str.Contains("Timeout") == false); // program ends with "Timeout" but we should never get there. + } + } + } +}