Add Hot Reload tests.
authorMikhail Kurinnoi <m.kurinnoi@samsung.com>
Mon, 30 May 2022 11:52:34 +0000 (14:52 +0300)
committerAlexander Soldatov/Platform Lab /SRR/Staff Engineer/Samsung Electronics <soldatov.a@samsung.com>
Tue, 7 Jun 2022 14:54:41 +0000 (17:54 +0300)
19 files changed:
src/managed/SymbolReader.cs
src/metadata/modules.cpp
test-suite/MITestHotReloadAsyncStepping/MITestHotReloadAsyncStepping.csproj [new file with mode: 0644]
test-suite/MITestHotReloadAsyncStepping/Program.cs [new file with mode: 0644]
test-suite/MITestHotReloadBreak/MITestHotReloadBreak.csproj [new file with mode: 0644]
test-suite/MITestHotReloadBreak/Program.cs [new file with mode: 0644]
test-suite/MITestHotReloadBreakpoint/Program.cs
test-suite/MITestHotReloadEvaluate/MITestHotReloadEvaluate.csproj [new file with mode: 0644]
test-suite/MITestHotReloadEvaluate/Program.cs [new file with mode: 0644]
test-suite/MITestHotReloadJMC/MITestHotReloadJMC.csproj [new file with mode: 0644]
test-suite/MITestHotReloadJMC/Program.cs [new file with mode: 0644]
test-suite/MITestHotReloadStepping/MITestHotReloadStepping.csproj [new file with mode: 0644]
test-suite/MITestHotReloadStepping/Program.cs [new file with mode: 0644]
test-suite/MITestHotReloadWithoutBreak/MITestHotReloadWithoutBreak.csproj [new file with mode: 0644]
test-suite/MITestHotReloadWithoutBreak/Program.cs [new file with mode: 0644]
test-suite/TestAppHotReload/Program.cs
test-suite/TestAppHotReloadAsync/Program.cs [new file with mode: 0644]
test-suite/TestAppHotReloadAsync/TestAppHotReloadAsync.csproj [new file with mode: 0644]
test-suite/sdb_run_tests.sh

index 6bfdc7e2e1ea786836ad817ab0926deadc75d00b..0fad911597a40b2549be1f01e4dd9836bb3a13cd 100644 (file)
@@ -603,7 +603,7 @@ namespace NetCoreDbg
                 }
 
                 if (ModuleData.Count == 0)
-                    return RetCode.Fail;
+                    return RetCode.OK;
 
                 int structModuleMethodsDataSize = Marshal.SizeOf<file_methods_data_t>();
                 module_methods_data_t managedData;
index 15098498ea8794763592eeb675e33defa414fd21..7f5a29fd60f762d7da940b29165985201973d7c5 100644 (file)
@@ -1487,8 +1487,12 @@ HRESULT Modules::ApplyPdbDelta(ICorDebugModule *pModule, bool needJMC, const std
 
     PVOID pSymbolReaderHandle = nullptr;
     IfFailRet(Interop::LoadDeltaPdb(deltaPDB, &pSymbolReaderHandle, methodTokens));
+    // Note, even if methodTokens is empty, pSymbolReaderHandle must be added into vector (we use indexes that correspond to il/metadata apply number + will care about release it in proper way).
     mdInfo.m_symbolReaderHandles.emplace_back(pSymbolReaderHandle);
 
+    if (methodTokens.empty())
+        return S_OK;
+
     if (needJMC)
         DisableJMCByAttributes(pModule, methodTokens);
 
diff --git a/test-suite/MITestHotReloadAsyncStepping/MITestHotReloadAsyncStepping.csproj b/test-suite/MITestHotReloadAsyncStepping/MITestHotReloadAsyncStepping.csproj
new file mode 100644 (file)
index 0000000..45e9571
--- /dev/null
@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+    <ProjectReference Include="..\TestAppHotReloadAsync\TestAppHotReloadAsync.csproj" />\r
+  </ItemGroup>\r
+\r
+  <PropertyGroup>\r
+    <OutputType>Exe</OutputType>\r
+    <TargetFramework>netcoreapp3.1</TargetFramework>\r
+  </PropertyGroup>\r
+\r
+</Project>\r
diff --git a/test-suite/MITestHotReloadAsyncStepping/Program.cs b/test-suite/MITestHotReloadAsyncStepping/Program.cs
new file mode 100644 (file)
index 0000000..3cf069f
--- /dev/null
@@ -0,0 +1,404 @@
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+    class Context\r
+    {\r
+        public void Prepare(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-run").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        bool IsStoppedEvent(MIOutOfBandRecord record)\r
+        {\r
+            if (record.Type != MIOutOfBandRecordType.Async) {\r
+                return false;\r
+            }\r
+\r
+            var asyncRecord = (MIAsyncRecord)record;\r
+\r
+            if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+                asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+                return false;\r
+            }\r
+\r
+            return true;\r
+        }\r
+\r
+        public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "entry-point-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var func = (MIConst)frame["func"];\r
+                if (func.CString == realNamespace + ".Program.<Main>d__0.MoveNext()") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasBreakpointHit(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "breakpoint-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var fileName = (MIConst)frame["file"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+\r
+                if (fileName.CString == bpFileName &&\r
+                    line == bpNumLine) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter),\r
+                        @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasStep(string caller_trace, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+                if (reason.CString != "end-stepping-range") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+                if (bpNumLine == line) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasStepInOutdatedCode(string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+                if (reason.CString != "end-stepping-range") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var func =  ((MIConst)frame["func"]).CString;\r
+\r
+                if (func.StartsWith("[Outdated Code]")) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasExit(string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "exited") {\r
+                    return false;\r
+                }\r
+\r
+                var exitCode = (MIConst)output["exit-code"];\r
+\r
+                if (exitCode.CString == "0") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void DebuggerExit(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Exit,\r
+                         MIDebugger.Request("-gdb-exit").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EnableBreakpoint(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-break-insert -f " + bpFileName + ":" + bpNumLine).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void Continue(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-continue").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void StepOver(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-next").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void StepIn(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-step").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void StepOut(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-finish").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostRuntimeVersion(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostOS(string caller_trace)\r
+        {\r
+            Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckTargetRuntimeVersion(string caller_trace)\r
+        {\r
+            var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+            Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+            Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+        }\r
+\r
+        public void StartGenDeltaSession(string caller_trace)\r
+        {\r
+            string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+            Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EndGenDeltaSession(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+        {\r
+            System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+            process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+            process.StartInfo.RedirectStandardInput = true;\r
+            process.StartInfo.RedirectStandardOutput = true;\r
+            process.StartInfo.CreateNoWindow = true;\r
+            process.StartInfo.UseShellExecute = false;\r
+            \r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+            {\r
+                process.StartInfo.FileName = "bash";\r
+                process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+            }\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            process.Start();\r
+            process.WaitForExit();\r
+            Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WriteDeltas(string caller_trace, string fileName)\r
+        {\r
+            string hostPath;\r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+                hostPath = Path.Combine(@"/tmp", fileName);\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            string targetPath = @"/tmp";\r
+            Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+        }\r
+\r
+        public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+        {\r
+            Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void ApplyDeltas(string caller_trace, string fileName)\r
+        {\r
+            string targetPath = Path.Combine(@"/tmp", fileName);\r
+            string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+        {\r
+            ControlInfo = controlInfo;\r
+            MIDebugger = new MIDebugger(debuggerClient);\r
+            GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+        }\r
+\r
+        ControlInfo ControlInfo;\r
+        MIDebugger MIDebugger;\r
+        GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+    }\r
+}\r
+\r
+namespace MITestHotReloadAsyncStepping\r
+{\r
+    class Program\r
+    {\r
+        static void Main(string[] args)\r
+        {\r
+            Label.Checkpoint("init", "test_stepin_new_code", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.CheckHostOS(@"__FILE__:__LINE__");\r
+                Context.Prepare(@"__FILE__:__LINE__");\r
+                Context.WasEntryPointHit("TestAppHotReloadAsync", @"__FILE__:__LINE__");\r
+                // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+                Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System;\r
+                using System.Threading.Tasks;\r
+                namespace TestAppHotReloadAsync\r
+                {\r
+                    class Program\r
+                    {\r
+                        static async Task Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World!"");\r
+                            await HotReloadTestAsync();\r
+                        }\r
+                        static async Task HotReloadTestAsync()\r
+                        {\r
+                            Console.WriteLine(""Updated string."");\r
+                            await HotReloadStepTest1Async();                                                 // line 15\r
+                        }\r
+                        static async Task HotReloadStepTest1Async()\r
+                        {                                                                                    // line 18\r
+                            Console.WriteLine(""Added line 1."");\r
+                            await Task.Delay(100);\r
+                            Console.WriteLine(""Added line 2."");\r
+                            await Task.Delay(100);\r
+                            Console.WriteLine(""Added line 3."");\r
+                        }\r
+                    }\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 15);\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            // Test step-in for new code.\r
+            Label.Checkpoint("test_stepin_new_code", "test_stepover_new_code", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 15);\r
+                Context.StepIn(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 18);\r
+            });\r
+\r
+            // Test step-over for new code.\r
+            Label.Checkpoint("test_stepover_new_code", "test_stepout_new_code", (Object context) => {\r
+                Context Context = (Context)context;\r
+  \r
+                Context.StepOver(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 19);\r
+                Context.StepOver(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 20);\r
+                Context.StepOver(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 21);\r
+            });\r
+\r
+            // Test step-out for new code.\r
+            Label.Checkpoint("test_stepout_new_code", "finish", (Object context) => {\r
+                Context Context = (Context)context;\r
+\r
+                Context.StepOut(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 16);\r
+\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("finish", "", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+                Context.WasExit(@"__FILE__:__LINE__");\r
+                Context.DebuggerExit(@"__FILE__:__LINE__");\r
+            });\r
+        }\r
+    }\r
+}\r
diff --git a/test-suite/MITestHotReloadBreak/MITestHotReloadBreak.csproj b/test-suite/MITestHotReloadBreak/MITestHotReloadBreak.csproj
new file mode 100644 (file)
index 0000000..b3d4e42
--- /dev/null
@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+    <ProjectReference Include="..\TestAppHotReload\TestAppHotReload.csproj" />\r
+  </ItemGroup>\r
+\r
+  <PropertyGroup>\r
+    <OutputType>Exe</OutputType>\r
+    <TargetFramework>netcoreapp3.1</TargetFramework>\r
+  </PropertyGroup>\r
+\r
+</Project>\r
diff --git a/test-suite/MITestHotReloadBreak/Program.cs b/test-suite/MITestHotReloadBreak/Program.cs
new file mode 100644 (file)
index 0000000..a835b51
--- /dev/null
@@ -0,0 +1,474 @@
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+    class Context\r
+    {\r
+        public void Prepare(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-run").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        bool IsStoppedEvent(MIOutOfBandRecord record)\r
+        {\r
+            if (record.Type != MIOutOfBandRecordType.Async) {\r
+                return false;\r
+            }\r
+\r
+            var asyncRecord = (MIAsyncRecord)record;\r
+\r
+            if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+                asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+                return false;\r
+            }\r
+\r
+            return true;\r
+        }\r
+\r
+        public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "entry-point-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var func = (MIConst)frame["func"];\r
+                if (func.CString == realNamespace + ".Program.Main()") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasBreakpointHit(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "breakpoint-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var fileName = (MIConst)frame["file"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+\r
+                if (fileName.CString == bpFileName &&\r
+                    line == bpNumLine) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter),\r
+                        @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasBreakHit(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+                var signal_name = (MIConst)output["signal-name"];\r
+\r
+                if (reason.CString != "signal-received" &&\r
+                    signal_name.CString != "SIGINT") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var fileName = (MIConst)frame["file"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+\r
+                if (fileName.CString == bpFileName &&\r
+                    line == bpNumLine) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasBreakHitInOutdatedCode(string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+                var signal_name = (MIConst)output["signal-name"];\r
+\r
+                if (reason.CString != "signal-received" &&\r
+                    signal_name.CString != "SIGINT") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var func =  ((MIConst)frame["func"]).CString;\r
+\r
+                if (func.StartsWith("[Outdated Code]")) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasStep(string caller_trace, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+                if (reason.CString != "end-stepping-range") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+                if (bpNumLine == line) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasExit(string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "exited") {\r
+                    return false;\r
+                }\r
+\r
+                var exitCode = (MIConst)output["exit-code"];\r
+\r
+                if (exitCode.CString == "0") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void DebuggerExit(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Exit,\r
+                         MIDebugger.Request("-gdb-exit").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EnableBreakpoint(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-break-insert -f " + bpFileName + ":" + bpNumLine).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void Continue(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-continue").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void StepOver(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-next").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostRuntimeVersion(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostOS(string caller_trace)\r
+        {\r
+            Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckTargetRuntimeVersion(string caller_trace)\r
+        {\r
+            var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+            Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+            Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+        }\r
+\r
+        public void StartGenDeltaSession(string caller_trace)\r
+        {\r
+            string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+            Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EndGenDeltaSession(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+        {\r
+            System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+            process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+            process.StartInfo.RedirectStandardInput = true;\r
+            process.StartInfo.RedirectStandardOutput = true;\r
+            process.StartInfo.CreateNoWindow = true;\r
+            process.StartInfo.UseShellExecute = false;\r
+            \r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+            {\r
+                process.StartInfo.FileName = "bash";\r
+                process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+            }\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            process.Start();\r
+            process.WaitForExit();\r
+            Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WriteDeltas(string caller_trace, string fileName)\r
+        {\r
+            string hostPath;\r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+                hostPath = Path.Combine(@"/tmp", fileName);\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            string targetPath = @"/tmp";\r
+            Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+        }\r
+\r
+        public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+        {\r
+            Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void ApplyDeltas(string caller_trace, string fileName)\r
+        {\r
+            string targetPath = Path.Combine(@"/tmp", fileName);\r
+            string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+        {\r
+            ControlInfo = controlInfo;\r
+            MIDebugger = new MIDebugger(debuggerClient);\r
+            GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+        }\r
+\r
+        ControlInfo ControlInfo;\r
+        MIDebugger MIDebugger;\r
+        GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+    }\r
+}\r
+\r
+namespace MITestHotReloadBreak\r
+{\r
+    class Program\r
+    {\r
+        static void Main(string[] args)\r
+        {\r
+            Label.Checkpoint("init", "break_test1", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.CheckHostOS(@"__FILE__:__LINE__");\r
+                Context.Prepare(@"__FILE__:__LINE__");\r
+                Context.WasEntryPointHit("TestAppHotReload", @"__FILE__:__LINE__");\r
+                // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+                Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 28);\r
+\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System;\r
+                using System.Diagnostics;\r
+                namespace TestAppHotReload\r
+                {\r
+                    class Program\r
+                    {\r
+                        static void Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World!"");\r
+                            HotReloadTest();\r
+                        }\r
+                        static void HotReloadTest()\r
+                        {\r
+                            Console.WriteLine(""Updated string."");\r
+                            HotReloadBreakTest1();\r
+                            HotReloadBreakTest2();\r
+                            HotReloadBreakTest3();\r
+                            Debugger.Break();\r
+                        }\r
+                        static void HotReloadBreakTest1()\r
+                        {\r
+                            Console.WriteLine(""Added break."");\r
+                            Debugger.Break();                                                                // line 23\r
+                        }\r
+                        static void HotReloadBreakTest2()\r
+                        {\r
+                            Console.WriteLine(""Added break + breakpoint (added before apply deltas)."");\r
+                            Debugger.Break();                                                                // line 28\r
+                            Console.WriteLine(""Added break + breakpoint (added after apply deltas)."");\r
+                            Debugger.Break();                                                                // line 30\r
+                        }\r
+                        static void HotReloadBreakTest3()\r
+                        {\r
+                            Console.WriteLine(""Added break + step."");                                      // line 34\r
+                            Debugger.Break();                                                                // line 35\r
+                        }                                                                                    // line 36\r
+                    }\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 30);\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 34);\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            // Test, that debugger stop at Debugger.Break() in managed code.\r
+            Label.Checkpoint("break_test1", "break_test2", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakHit(@"__FILE__:__LINE__", @"Program.cs", 23);\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            // Test, that debugger ignore Debugger.Break() on continue in case it already stop at breakpoint at this code line.\r
+            Label.Checkpoint("break_test2", "break_test3", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 28);\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 30);\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            // Test, that debugger ignore Debugger.Break() on step in case it already stop at step at this code.\r
+            Label.Checkpoint("break_test3", "break_test4", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 34);\r
+                Context.StepOver(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 35);\r
+                Context.StepOver(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 36);\r
+            });\r
+\r
+            // Stop on Break in outdated code.\r
+            Label.Checkpoint("break_test4", "finish", (Object context) => {\r
+                Context Context = (Context)context;\r
+\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System;\r
+                using System.Diagnostics;\r
+                namespace TestAppHotReload\r
+                {\r
+                    class Program\r
+                    {\r
+                        static void Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World!"");\r
+                            HotReloadTest();\r
+                        }\r
+                        static void HotReloadTest()\r
+                        {\r
+                        }\r
+                        static void HotReloadBreakTest1()\r
+                        {\r
+                        }\r
+                        static void HotReloadBreakTest2()\r
+                        {\r
+                        }\r
+                        static void HotReloadBreakTest3()\r
+                        {\r
+                        }\r
+                    }\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+\r
+                Context.WasBreakHitInOutdatedCode(@"__FILE__:__LINE__");\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("finish", "", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+                Context.WasExit(@"__FILE__:__LINE__");\r
+                Context.DebuggerExit(@"__FILE__:__LINE__");\r
+            });\r
+        }\r
+    }\r
+}\r
index 4a00e7c9b0afdf3a03eebe54cc0144854903f772..1961249340395b1831b29db36f148c080fb87d11 100644 (file)
@@ -156,25 +156,6 @@ namespace NetcoreDbgTest.Script
                          @"__FILE__:__LINE__"+"\n"+caller_trace);\r
         }\r
 \r
-        public string GetAndCheckValue(string caller_trace, string ExpectedResult, string ExpectedType, string Expression)\r
-        {\r
-            var res = MIDebugger.Request(String.Format("-var-create - * \"{0}\"", Expression));\r
-            Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
-\r
-            Assert.Equal(Expression, ((MIConst)res["exp"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
-            Assert.Equal(ExpectedType, ((MIConst)res["type"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
-            Assert.Equal(ExpectedResult, ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
-\r
-            return ((MIConst)res["name"]).CString;\r
-        }\r
-\r
-        public void CheckErrorAtRequest(string caller_trace, string Expression, string errMsgStart)\r
-        {\r
-            var res = MIDebugger.Request(String.Format("-var-create - * \"{0}\"", Expression));\r
-            Assert.Equal(MIResultClass.Error, res.Class, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
-            Assert.True(((MIConst)res["msg"]).CString.StartsWith(errMsgStart), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
-        }\r
-\r
         public void CheckHostRuntimeVersion(string caller_trace)\r
         {\r
             Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
@@ -248,8 +229,9 @@ namespace NetcoreDbgTest.Script
         public void ApplyDeltas(string caller_trace, string fileName)\r
         {\r
             string targetPath = Path.Combine(@"/tmp", fileName);\r
+            string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
             Assert.Equal(MIResultClass.Done,\r
-                         MIDebugger.Request("-apply-deltas TestAppHotReload.dll " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+                         MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
                          @"__FILE__:__LINE__"+"\n"+caller_trace);\r
         }\r
 \r
@@ -282,6 +264,10 @@ namespace MITestHotReloadBreakpoint
                 Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
                 Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
 \r
+                // Debugger should remove breakpoint from old code and we never stop on it during old code execution.\r
+                // Note, at `Main()` update we execute `Main()` code (we stopped at entry point), so, we continue old `Main()` code execution.\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 8);\r
+\r
                 Context.GetDelta(@"__FILE__:__LINE__",\r
                 @"using System;\r
                 namespace TestAppHotReload\r
@@ -290,18 +276,18 @@ namespace MITestHotReloadBreakpoint
                     {\r
                         static void Main(string[] args)\r
                         {\r
-                            Console.WriteLine(""Hello World!"");\r
+                            Console.WriteLine(""Hello World! Main updated."");                               // line 8\r
                             HotReloadTest();\r
                         }\r
                         static void HotReloadTest()\r
                         {\r
                             Console.WriteLine(""Updated string."");\r
-                            HotReloadEvalTest1();\r
-                            HotReloadEvalTest1();\r
-                        }\r
-                        static void HotReloadEvalTest1()\r
+                            HotReloadBreakpointTest1();\r
+                            HotReloadBreakpointTest1();                                                      // line 15\r
+                        }                                                                                    // line 16\r
+                        static void HotReloadBreakpointTest1()\r
                         {\r
-                            Console.WriteLine(""Added string."");\r
+                            Console.WriteLine(""Added string."");                                            // line 19\r
                         }\r
                     }\r
                 }", @"Program.cs");\r
@@ -320,8 +306,8 @@ namespace MITestHotReloadBreakpoint
                 Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 16);\r
                 Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 19);\r
                 Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 25);\r
-                Context.EnableFuncBreakpoint(@"__FILE__:__LINE__", "Program.HotReloadEvalTest1");\r
-                Context.EnableFuncBreakpoint(@"__FILE__:__LINE__", "Program.HotReloadEvalTest2");\r
+                Context.EnableFuncBreakpoint(@"__FILE__:__LINE__", "Program.HotReloadBreakpointTest1");\r
+                Context.EnableFuncBreakpoint(@"__FILE__:__LINE__", "Program.HotReloadBreakpointTest2");\r
 \r
                 Context.GetDelta(@"__FILE__:__LINE__",\r
                 @"using System;\r
@@ -337,18 +323,18 @@ namespace MITestHotReloadBreakpoint
                         static void HotReloadTest()\r
                         {\r
                             Console.WriteLine(""Updated string."");\r
-                            HotReloadEvalTest1();\r
-                            HotReloadEvalTest1();\r
+                            HotReloadBreakpointTest1();\r
+                            HotReloadBreakpointTest1();                                                      // line 15\r
                         }\r
-                        static void HotReloadEvalTest1()\r
+                        static void HotReloadBreakpointTest1()\r
                         {\r
-                            Console.WriteLine(""Updated added string."");\r
-                            HotReloadEvalTest2();\r
+                            Console.WriteLine(""Updated added string."");                                    // line 19\r
+                            HotReloadBreakpointTest2();\r
                         }\r
-                        static void HotReloadEvalTest2()\r
+                        static void HotReloadBreakpointTest2()\r
                         {\r
                             Console.WriteLine(""Another added string."");\r
-                            Console.WriteLine(""One more added string."");\r
+                            Console.WriteLine(""One more added string."");                                   // line 25\r
                         }\r
                     }\r
                 }", @"Program.cs");\r
@@ -360,7 +346,7 @@ namespace MITestHotReloadBreakpoint
 \r
             Label.Checkpoint("bp_test_old_func_resetup", "bp_test_old_line_resetup", (Object context) => {\r
                 Context Context = (Context)context;\r
-                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 18); // Program.HotReloadEvalTest1\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 18); // Program.HotReloadBreakpointTest1\r
                 Context.Continue(@"__FILE__:__LINE__");\r
             });\r
 \r
@@ -372,7 +358,7 @@ namespace MITestHotReloadBreakpoint
 \r
             Label.Checkpoint("bp_test_func_added", "bp_test_line_added", (Object context) => {\r
                 Context Context = (Context)context;\r
-                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 23); // Program.HotReloadEvalTest2\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 23); // Program.HotReloadBreakpointTest2\r
                 Context.Continue(@"__FILE__:__LINE__");\r
             });\r
 \r
diff --git a/test-suite/MITestHotReloadEvaluate/MITestHotReloadEvaluate.csproj b/test-suite/MITestHotReloadEvaluate/MITestHotReloadEvaluate.csproj
new file mode 100644 (file)
index 0000000..b3d4e42
--- /dev/null
@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+    <ProjectReference Include="..\TestAppHotReload\TestAppHotReload.csproj" />\r
+  </ItemGroup>\r
+\r
+  <PropertyGroup>\r
+    <OutputType>Exe</OutputType>\r
+    <TargetFramework>netcoreapp3.1</TargetFramework>\r
+  </PropertyGroup>\r
+\r
+</Project>\r
diff --git a/test-suite/MITestHotReloadEvaluate/Program.cs b/test-suite/MITestHotReloadEvaluate/Program.cs
new file mode 100644 (file)
index 0000000..2dc1698
--- /dev/null
@@ -0,0 +1,440 @@
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+    class Context\r
+    {\r
+        public void Prepare(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-run").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        bool IsStoppedEvent(MIOutOfBandRecord record)\r
+        {\r
+            if (record.Type != MIOutOfBandRecordType.Async) {\r
+                return false;\r
+            }\r
+\r
+            var asyncRecord = (MIAsyncRecord)record;\r
+\r
+            if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+                asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+                return false;\r
+            }\r
+\r
+            return true;\r
+        }\r
+\r
+        public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "entry-point-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var func = (MIConst)frame["func"];\r
+                if (func.CString == realNamespace + ".Program.Main()") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasBreakpointHit(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "breakpoint-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var fileName = (MIConst)frame["file"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+\r
+                if (fileName.CString == bpFileName &&\r
+                    line == bpNumLine) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter),\r
+                        @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasExit(string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "exited") {\r
+                    return false;\r
+                }\r
+\r
+                var exitCode = (MIConst)output["exit-code"];\r
+\r
+                if (exitCode.CString == "0") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void DebuggerExit(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Exit,\r
+                         MIDebugger.Request("-gdb-exit").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EnableBreakpoint(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-break-insert -f " + bpFileName + ":" + bpNumLine).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void Continue(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-continue").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public string GetAndCheckValue(string caller_trace, string ExpectedResult, string ExpectedType, string Expression)\r
+        {\r
+            var res = MIDebugger.Request(String.Format("-var-create - * \"{0}\"", Expression));\r
+            Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(Expression, ((MIConst)res["exp"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+            Assert.Equal(ExpectedType, ((MIConst)res["type"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+            Assert.Equal(ExpectedResult, ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            return ((MIConst)res["name"]).CString;\r
+        }\r
+\r
+        public void CheckErrorAtRequest(string caller_trace, string Expression, string errMsgStart)\r
+        {\r
+            var res = MIDebugger.Request(String.Format("-var-create - * \"{0}\"", Expression));\r
+            Assert.Equal(MIResultClass.Error, res.Class, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+            Assert.True(((MIConst)res["msg"]).CString.StartsWith(errMsgStart), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostRuntimeVersion(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostOS(string caller_trace)\r
+        {\r
+            Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckTargetRuntimeVersion(string caller_trace)\r
+        {\r
+            var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+            Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+            Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+        }\r
+\r
+        public void StartGenDeltaSession(string caller_trace)\r
+        {\r
+            string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+            Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EndGenDeltaSession(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+        {\r
+            System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+            process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+            process.StartInfo.RedirectStandardInput = true;\r
+            process.StartInfo.RedirectStandardOutput = true;\r
+            process.StartInfo.CreateNoWindow = true;\r
+            process.StartInfo.UseShellExecute = false;\r
+            \r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+            {\r
+                process.StartInfo.FileName = "bash";\r
+                process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+            }\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            process.Start();\r
+            process.WaitForExit();\r
+            Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WriteDeltas(string caller_trace, string fileName)\r
+        {\r
+            string hostPath;\r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+                hostPath = Path.Combine(@"/tmp", fileName);\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            string targetPath = @"/tmp";\r
+            Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+        }\r
+\r
+        public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+        {\r
+            Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void ApplyDeltas(string caller_trace, string fileName)\r
+        {\r
+            string targetPath = Path.Combine(@"/tmp", fileName);\r
+            string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+        {\r
+            ControlInfo = controlInfo;\r
+            MIDebugger = new MIDebugger(debuggerClient);\r
+            GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+        }\r
+\r
+        ControlInfo ControlInfo;\r
+        MIDebugger MIDebugger;\r
+        GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+    }\r
+}\r
+\r
+namespace MITestHotReloadEvaluate\r
+{\r
+    class Program\r
+    {\r
+        static void Main(string[] args)\r
+        {\r
+            Label.Checkpoint("init", "eval_test1", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.CheckHostOS(@"__FILE__:__LINE__");\r
+                Context.Prepare(@"__FILE__:__LINE__");\r
+                Context.WasEntryPointHit("TestAppHotReload", @"__FILE__:__LINE__");\r
+                // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+                Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System;\r
+                namespace TestAppHotReload\r
+                {\r
+                    class TestClass\r
+                    {\r
+                        int i = 5;\r
+                    }\r
+\r
+                    class Program\r
+                    {\r
+                        static int iStatic = 10;\r
+\r
+                        static void Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World!"");\r
+                            HotReloadTest();\r
+                        }\r
+                        static void HotReloadTest()\r
+                        {\r
+                            Console.WriteLine(""Updated string."");\r
+                            HotReloadEvalTest1(555);\r
+                            HotReloadEvalTest1(555);\r
+                        }\r
+                        static void HotReloadEvalTest1(int iArg)\r
+                        {\r
+                            int iLocal = 22;\r
+                            var clLocal = new TestClass();\r
+                            Console.WriteLine(""iArg="" + iArg.ToString());\r
+                            Console.WriteLine(""iLocal="" + iLocal.ToString());\r
+                            Console.WriteLine(""iStatic="" + iStatic.ToString());\r
+                            {\r
+                                int iLocalScope = 33;\r
+                                Console.WriteLine(""iLocalScope="" + iLocalScope.ToString());                // line 33\r
+                            }\r
+                        }                                                                                    // line 35\r
+                    }\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 33);\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 35);\r
+\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("eval_test1", "eval_test2", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 33);\r
+\r
+                // Check argument in added method.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "555", "int", "iArg");\r
+                // Check local variable in added method.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "22", "int", "iLocal");\r
+                // Check local variable in scope in added method.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "33", "int", "iLocalScope");\r
+                // Check added static field.\r
+                // Note, it have `0` since static constructor was called before we add this field.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "0", "int", "iStatic");\r
+                // Check field in added class.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "clLocal.i");\r
+\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("eval_test2", "eval_test3", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 35);\r
+\r
+                // Check argument in added method.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "555", "int", "iArg");\r
+                // Check local variable in added method.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "22", "int", "iLocal");\r
+                // Check local variable out of scope in added method.\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "iLocalScope", "error");\r
+                // Check added static field.\r
+                // Note, it have `0` since static constructor was called before we add this field.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "0", "int", "iStatic");\r
+                // Check field in added class.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "clLocal.i");\r
+            });\r
+\r
+            Label.Checkpoint("eval_test3", "eval_test4", (Object context) => {\r
+                Context Context = (Context)context;\r
+\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System;\r
+                namespace TestAppHotReload\r
+                {\r
+                    class TestClass\r
+                    {\r
+                        int i = 5;\r
+                    }\r
+\r
+                    class Program\r
+                    {\r
+                        static int iStatic = 10;\r
+\r
+                        static void Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World!"");\r
+                            HotReloadTest();\r
+                        }\r
+                        static void HotReloadTest()\r
+                        {\r
+                            Console.WriteLine(""Updated string."");\r
+                            HotReloadEvalTest1(555);\r
+                            HotReloadEvalTest1(555);\r
+                        }\r
+                        static void HotReloadEvalTest1(int iArg)\r
+                        {                                                                                    // line 25\r
+                        }\r
+                    }\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+\r
+                // Check argument in added method.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "555", "int", "iArg");\r
+                // Check local variable in added method.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "22", "int", "iLocal");\r
+                // Check local variable out of scope in added method.\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "iLocalScope", "error");\r
+                // Check added static field.\r
+                // Note, it have `0` since static constructor was called before we add this field.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "0", "int", "iStatic");\r
+                // Check field in added class.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "5", "int", "clLocal.i");\r
+\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 25);\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("eval_test4", "finish", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 25);\r
+\r
+                // Check argument in added method.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "555", "int", "iArg");\r
+                // Check local variable in added method.\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "iLocal", "error");\r
+                // Check local variable out of scope in added method.\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "iLocalScope", "error");\r
+                // Check added static field.\r
+                // Note, it have `0` since static constructor was called before we add this field.\r
+                Context.GetAndCheckValue(@"__FILE__:__LINE__", "0", "int", "iStatic");\r
+                // Check field in added class.\r
+                Context.CheckErrorAtRequest(@"__FILE__:__LINE__", "clLocal.i", "error");\r
+\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("finish", "", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+                Context.WasExit(@"__FILE__:__LINE__");\r
+                Context.DebuggerExit(@"__FILE__:__LINE__");\r
+            });\r
+        }\r
+    }\r
+}\r
diff --git a/test-suite/MITestHotReloadJMC/MITestHotReloadJMC.csproj b/test-suite/MITestHotReloadJMC/MITestHotReloadJMC.csproj
new file mode 100644 (file)
index 0000000..b3d4e42
--- /dev/null
@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+    <ProjectReference Include="..\TestAppHotReload\TestAppHotReload.csproj" />\r
+  </ItemGroup>\r
+\r
+  <PropertyGroup>\r
+    <OutputType>Exe</OutputType>\r
+    <TargetFramework>netcoreapp3.1</TargetFramework>\r
+  </PropertyGroup>\r
+\r
+</Project>\r
diff --git a/test-suite/MITestHotReloadJMC/Program.cs b/test-suite/MITestHotReloadJMC/Program.cs
new file mode 100644 (file)
index 0000000..72469f6
--- /dev/null
@@ -0,0 +1,399 @@
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+    class Context\r
+    {\r
+        public void Prepare(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            // Explicitly enable JMC for this test.\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-gdb-set just-my-code 1").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-run").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        bool IsStoppedEvent(MIOutOfBandRecord record)\r
+        {\r
+            if (record.Type != MIOutOfBandRecordType.Async) {\r
+                return false;\r
+            }\r
+\r
+            var asyncRecord = (MIAsyncRecord)record;\r
+\r
+            if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+                asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+                return false;\r
+            }\r
+\r
+            return true;\r
+        }\r
+\r
+        public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "entry-point-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var func = (MIConst)frame["func"];\r
+                if (func.CString == realNamespace + ".Program.Main()") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasBreakpointHit(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "breakpoint-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var fileName = (MIConst)frame["file"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+\r
+                if (fileName.CString == bpFileName &&\r
+                    line == bpNumLine) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter),\r
+                        @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasStep(string caller_trace, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+                if (reason.CString != "end-stepping-range") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+                if (bpNumLine == line) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasExit(string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "exited") {\r
+                    return false;\r
+                }\r
+\r
+                var exitCode = (MIConst)output["exit-code"];\r
+\r
+                if (exitCode.CString == "0") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void DebuggerExit(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Exit,\r
+                         MIDebugger.Request("-gdb-exit").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EnableBreakpoint(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-break-insert -f " + bpFileName + ":" + bpNumLine).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void Continue(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-continue").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void StepIn(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-step").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostRuntimeVersion(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostOS(string caller_trace)\r
+        {\r
+            Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckTargetRuntimeVersion(string caller_trace)\r
+        {\r
+            var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+            Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+            Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+        }\r
+\r
+        public void StartGenDeltaSession(string caller_trace)\r
+        {\r
+            string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+            Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EndGenDeltaSession(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+        {\r
+            System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+            process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+            process.StartInfo.RedirectStandardInput = true;\r
+            process.StartInfo.RedirectStandardOutput = true;\r
+            process.StartInfo.CreateNoWindow = true;\r
+            process.StartInfo.UseShellExecute = false;\r
+            \r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+            {\r
+                process.StartInfo.FileName = "bash";\r
+                process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+            }\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            process.Start();\r
+            process.WaitForExit();\r
+            Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WriteDeltas(string caller_trace, string fileName)\r
+        {\r
+            string hostPath;\r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+                hostPath = Path.Combine(@"/tmp", fileName);\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            string targetPath = @"/tmp";\r
+            Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+        }\r
+\r
+        public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+        {\r
+            Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void ApplyDeltas(string caller_trace, string fileName)\r
+        {\r
+            string targetPath = Path.Combine(@"/tmp", fileName);\r
+            string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+        {\r
+            ControlInfo = controlInfo;\r
+            MIDebugger = new MIDebugger(debuggerClient);\r
+            GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+        }\r
+\r
+        ControlInfo ControlInfo;\r
+        MIDebugger MIDebugger;\r
+        GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+    }\r
+}\r
+\r
+namespace MITestHotReloadJMC\r
+{\r
+    class Program\r
+    {\r
+        static void Main(string[] args)\r
+        {\r
+            Label.Checkpoint("init", "test_breakpoints", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.CheckHostOS(@"__FILE__:__LINE__");\r
+                Context.Prepare(@"__FILE__:__LINE__");\r
+                Context.WasEntryPointHit("TestAppHotReload", @"__FILE__:__LINE__");\r
+                // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+                Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System;using System.Diagnostics;\r
+                namespace TestAppHotReload\r
+                {\r
+                    class Program\r
+                    {\r
+                        static void Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World!"");\r
+                            HotReloadTest();\r
+                        }\r
+                        static void HotReloadTest()\r
+                        {\r
+                            Console.WriteLine(""Updated string."");\r
+                            test_attr_func1();\r
+                            test_attr_func2();\r
+                            test_attr_func3();\r
+                            ctest_attr1.test_func();\r
+                            ctest_attr2.test_func();\r
+                            test_attr_func1();                                                               // line 19\r
+                            test_attr_func2();                                                               // line 20\r
+                            test_attr_func3();                                                               // line 21\r
+                            ctest_attr1.test_func();                                                         // line 22\r
+                            ctest_attr2.test_func();                                                         // line 23\r
+                        }                                                                                    // line 24\r
+\r
+                        [DebuggerStepThroughAttribute()]\r
+                        static void test_attr_func1()\r
+                        {                                                                                    // line 28\r
+                        }\r
+\r
+                        [DebuggerNonUserCodeAttribute()]\r
+                        static void test_attr_func2()\r
+                        {                                                                                    // line 33\r
+                        }\r
+\r
+                        [DebuggerHiddenAttribute()]\r
+                        static void test_attr_func3()\r
+                        {                                                                                    // line 38\r
+                        }\r
+                    }\r
+\r
+                    [DebuggerStepThroughAttribute()]\r
+                    class ctest_attr1\r
+                    {\r
+                        public static void test_func()\r
+                        {                                                                                    // line 46\r
+                        }\r
+                    }\r
+\r
+                    [DebuggerNonUserCodeAttribute()]\r
+                    class ctest_attr2\r
+                    {\r
+                        public static void test_func()\r
+                        {                                                                                    // line 54\r
+                        }\r
+                    }\r
+\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 19);\r
+            });\r
+\r
+            Label.Checkpoint("test_breakpoints", "test_stepping", (Object context) => {\r
+                Context Context = (Context)context;\r
+\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 28);\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 33);\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 38);\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 46);\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 54);\r
+\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("test_stepping", "finish", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 19);\r
+\r
+                Context.StepIn(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 20);\r
+                Context.StepIn(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 21);\r
+                Context.StepIn(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 22);\r
+                Context.StepIn(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 23);\r
+                Context.StepIn(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 24);\r
+\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("finish", "", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+                Context.WasExit(@"__FILE__:__LINE__");\r
+                Context.DebuggerExit(@"__FILE__:__LINE__");\r
+            });\r
+        }\r
+    }\r
+}\r
diff --git a/test-suite/MITestHotReloadStepping/MITestHotReloadStepping.csproj b/test-suite/MITestHotReloadStepping/MITestHotReloadStepping.csproj
new file mode 100644 (file)
index 0000000..b3d4e42
--- /dev/null
@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+    <ProjectReference Include="..\TestAppHotReload\TestAppHotReload.csproj" />\r
+  </ItemGroup>\r
+\r
+  <PropertyGroup>\r
+    <OutputType>Exe</OutputType>\r
+    <TargetFramework>netcoreapp3.1</TargetFramework>\r
+  </PropertyGroup>\r
+\r
+</Project>\r
diff --git a/test-suite/MITestHotReloadStepping/Program.cs b/test-suite/MITestHotReloadStepping/Program.cs
new file mode 100644 (file)
index 0000000..e660e2e
--- /dev/null
@@ -0,0 +1,445 @@
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+    class Context\r
+    {\r
+        public void Prepare(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-run").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        bool IsStoppedEvent(MIOutOfBandRecord record)\r
+        {\r
+            if (record.Type != MIOutOfBandRecordType.Async) {\r
+                return false;\r
+            }\r
+\r
+            var asyncRecord = (MIAsyncRecord)record;\r
+\r
+            if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+                asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+                return false;\r
+            }\r
+\r
+            return true;\r
+        }\r
+\r
+        public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "entry-point-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var func = (MIConst)frame["func"];\r
+                if (func.CString == realNamespace + ".Program.Main()") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasBreakpointHit(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "breakpoint-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var fileName = (MIConst)frame["file"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+\r
+                if (fileName.CString == bpFileName &&\r
+                    line == bpNumLine) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter),\r
+                        @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasStep(string caller_trace, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+                if (reason.CString != "end-stepping-range") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+                if (bpNumLine == line) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasStepInOutdatedCode(string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+                if (reason.CString != "end-stepping-range") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var func =  ((MIConst)frame["func"]).CString;\r
+\r
+                if (func.StartsWith("[Outdated Code]")) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasExit(string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "exited") {\r
+                    return false;\r
+                }\r
+\r
+                var exitCode = (MIConst)output["exit-code"];\r
+\r
+                if (exitCode.CString == "0") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void DebuggerExit(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Exit,\r
+                         MIDebugger.Request("-gdb-exit").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EnableBreakpoint(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-break-insert -f " + bpFileName + ":" + bpNumLine).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void Continue(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-continue").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void StepOver(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-next").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void StepIn(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-step").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void StepOut(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-finish").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostRuntimeVersion(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostOS(string caller_trace)\r
+        {\r
+            Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckTargetRuntimeVersion(string caller_trace)\r
+        {\r
+            var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+            Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+            Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+        }\r
+\r
+        public void StartGenDeltaSession(string caller_trace)\r
+        {\r
+            string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+            Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EndGenDeltaSession(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+        {\r
+            System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+            process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+            process.StartInfo.RedirectStandardInput = true;\r
+            process.StartInfo.RedirectStandardOutput = true;\r
+            process.StartInfo.CreateNoWindow = true;\r
+            process.StartInfo.UseShellExecute = false;\r
+            \r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+            {\r
+                process.StartInfo.FileName = "bash";\r
+                process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+            }\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            process.Start();\r
+            process.WaitForExit();\r
+            Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WriteDeltas(string caller_trace, string fileName)\r
+        {\r
+            string hostPath;\r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+                hostPath = Path.Combine(@"/tmp", fileName);\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            string targetPath = @"/tmp";\r
+            Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+        }\r
+\r
+        public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+        {\r
+            Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void ApplyDeltas(string caller_trace, string fileName)\r
+        {\r
+            string targetPath = Path.Combine(@"/tmp", fileName);\r
+            string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+        {\r
+            ControlInfo = controlInfo;\r
+            MIDebugger = new MIDebugger(debuggerClient);\r
+            GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+        }\r
+\r
+        ControlInfo ControlInfo;\r
+        MIDebugger MIDebugger;\r
+        GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+    }\r
+}\r
+\r
+namespace MITestHotReloadStepping\r
+{\r
+    class Program\r
+    {\r
+        static void Main(string[] args)\r
+        {\r
+            Label.Checkpoint("init", "test_stepin_new_code", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.CheckHostOS(@"__FILE__:__LINE__");\r
+                Context.Prepare(@"__FILE__:__LINE__");\r
+                Context.WasEntryPointHit("TestAppHotReload", @"__FILE__:__LINE__");\r
+                // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+                Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System;\r
+                namespace TestAppHotReload\r
+                {\r
+                    class Program\r
+                    {\r
+                        static void Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World!"");\r
+                            HotReloadTest();\r
+                        }\r
+                        static void HotReloadTest()\r
+                        {\r
+                            Console.WriteLine(""Updated string."");\r
+                            HotReloadStepTest1();                                                            // line 14\r
+                            HotReloadStepTest1();\r
+                        }\r
+                        static void HotReloadStepTest1()\r
+                        {                                                                                    // line 18\r
+                            Console.WriteLine(""Added line 1."");\r
+                            Console.WriteLine(""Added line 2."");\r
+                            Console.WriteLine(""Added line 3."");\r
+                        }\r
+                    }\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 14);\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            // Test step-in for new code.\r
+            Label.Checkpoint("test_stepin_new_code", "update_code", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 14);\r
+                Context.StepIn(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 18);\r
+            });\r
+\r
+            Label.Checkpoint("update_code", "test_stepover_old_code", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System;\r
+                namespace TestAppHotReload\r
+                {\r
+                    class Program\r
+                    {\r
+                        static void Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World!"");\r
+                            HotReloadTest();\r
+                        }\r
+                        static void HotReloadTest()\r
+                        {\r
+                            Console.WriteLine(""Updated string."");\r
+                            HotReloadStepTest1();\r
+                            HotReloadStepTest1();                                                            // line 15\r
+                        }\r
+                        static void HotReloadStepTest1()\r
+                        {                                                                                    // line 18\r
+                            Console.WriteLine(""Updated line, removed 2 lines."");\r
+                        }\r
+                    }\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+            });\r
+\r
+            // Test step-over for old code.\r
+            Label.Checkpoint("test_stepover_old_code", "test_stepover_new_code", (Object context) => {\r
+                Context Context = (Context)context;\r
+\r
+                Context.StepOver(@"__FILE__:__LINE__");\r
+                Context.WasStepInOutdatedCode(@"__FILE__:__LINE__");\r
+                Context.StepOver(@"__FILE__:__LINE__");\r
+                Context.WasStepInOutdatedCode(@"__FILE__:__LINE__");\r
+                Context.StepOver(@"__FILE__:__LINE__");\r
+                Context.WasStepInOutdatedCode(@"__FILE__:__LINE__");\r
+\r
+                Context.EnableBreakpoint(@"__FILE__:__LINE__", @"Program.cs", 15);\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            // Test step-over for new code.\r
+            Label.Checkpoint("test_stepover_new_code", "test_stepout_new_code", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakpointHit(@"__FILE__:__LINE__", @"Program.cs", 15);\r
+\r
+                Context.StepIn(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 18);\r
+                Context.StepOver(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 19);\r
+            });\r
+\r
+            // Test step-out for new code.\r
+            Label.Checkpoint("test_stepout_new_code", "finish", (Object context) => {\r
+                Context Context = (Context)context;\r
+\r
+                Context.StepOut(@"__FILE__:__LINE__");\r
+                Context.WasStep(@"__FILE__:__LINE__", 16);\r
+\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("finish", "", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+                Context.WasExit(@"__FILE__:__LINE__");\r
+                Context.DebuggerExit(@"__FILE__:__LINE__");\r
+            });\r
+        }\r
+    }\r
+}\r
diff --git a/test-suite/MITestHotReloadWithoutBreak/MITestHotReloadWithoutBreak.csproj b/test-suite/MITestHotReloadWithoutBreak/MITestHotReloadWithoutBreak.csproj
new file mode 100644 (file)
index 0000000..b3d4e42
--- /dev/null
@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+  <ItemGroup>\r
+    <ProjectReference Include="..\NetcoreDbgTest\NetcoreDbgTest.csproj" />\r
+    <ProjectReference Include="..\TestAppHotReload\TestAppHotReload.csproj" />\r
+  </ItemGroup>\r
+\r
+  <PropertyGroup>\r
+    <OutputType>Exe</OutputType>\r
+    <TargetFramework>netcoreapp3.1</TargetFramework>\r
+  </PropertyGroup>\r
+\r
+</Project>\r
diff --git a/test-suite/MITestHotReloadWithoutBreak/Program.cs b/test-suite/MITestHotReloadWithoutBreak/Program.cs
new file mode 100644 (file)
index 0000000..d6eb396
--- /dev/null
@@ -0,0 +1,375 @@
+using System;\r
+using System.IO;\r
+using System.Runtime.InteropServices;\r
+\r
+using NetcoreDbgTest;\r
+using NetcoreDbgTest.MI;\r
+using NetcoreDbgTest.Script;\r
+using NetcoreDbgTest.GetDeltaApi;\r
+\r
+namespace NetcoreDbgTest.Script\r
+{\r
+    class Context\r
+    {\r
+        public void Prepare(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-gdb-set enable-hot-reload 1").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-file-exec-and-symbols " + ControlInfo.CorerunPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-exec-arguments " + ControlInfo.TargetAssemblyPath).Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-run").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        bool IsStoppedEvent(MIOutOfBandRecord record)\r
+        {\r
+            if (record.Type != MIOutOfBandRecordType.Async) {\r
+                return false;\r
+            }\r
+\r
+            var asyncRecord = (MIAsyncRecord)record;\r
+\r
+            if (asyncRecord.Class != MIAsyncRecordClass.Exec ||\r
+                asyncRecord.Output.Class != MIAsyncOutputClass.Stopped) {\r
+                return false;\r
+            }\r
+\r
+            return true;\r
+        }\r
+\r
+        public void WasEntryPointHit(string realNamespace, string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "entry-point-hit") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var func = (MIConst)frame["func"];\r
+                if (func.CString == realNamespace + ".Program.Main()") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasBreakHit(string caller_trace, string bpFileName, int bpNumLine)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+                var signal_name = (MIConst)output["signal-name"];\r
+\r
+                if (reason.CString != "signal-received" &&\r
+                    signal_name.CString != "SIGINT") {\r
+                    return false;\r
+                }\r
+\r
+                var frame = (MITuple)output["frame"];\r
+                var fileName = (MIConst)frame["file"];\r
+                var line = ((MIConst)frame["line"]).Int;\r
+\r
+                if (fileName.CString == bpFileName &&\r
+                    line == bpNumLine) {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WasExit(string caller_trace)\r
+        {\r
+            Func<MIOutOfBandRecord, bool> filter = (record) => {\r
+                if (!IsStoppedEvent(record)) {\r
+                    return false;\r
+                }\r
+\r
+                var output = ((MIAsyncRecord)record).Output;\r
+                var reason = (MIConst)output["reason"];\r
+\r
+                if (reason.CString != "exited") {\r
+                    return false;\r
+                }\r
+\r
+                var exitCode = (MIConst)output["exit-code"];\r
+\r
+                if (exitCode.CString == "0") {\r
+                    return true;\r
+                }\r
+\r
+                return false;\r
+            };\r
+\r
+            Assert.True(MIDebugger.IsEventReceived(filter), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void DebuggerExit(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Exit,\r
+                         MIDebugger.Request("-gdb-exit").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void Continue(string caller_trace)\r
+        {\r
+            Assert.Equal(MIResultClass.Running,\r
+                         MIDebugger.Request("-exec-continue").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostRuntimeVersion(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.CheckRuntimeVersion(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckHostOS(string caller_trace)\r
+        {\r
+            Assert.True(RuntimeInformation.IsOSPlatform(OSPlatform.Linux), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void CheckTargetRuntimeVersion(string caller_trace)\r
+        {\r
+            var res = MIDebugger.Request("-var-create - * System.Environment.Version.Major>=6");\r
+            Assert.Equal(MIResultClass.Done, res.Class, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+            Assert.Equal("true", ((MIConst)res["value"]).CString, @"__FILE__:__LINE__"+"\n" + caller_trace);\r
+        }\r
+\r
+        public void StartGenDeltaSession(string caller_trace)\r
+        {\r
+            string projectPath = Path.GetDirectoryName(ControlInfo.SourceFilesPath);\r
+            Assert.True(GetDeltaApi.StartGenDeltaSession(projectPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void EndGenDeltaSession(string caller_trace)\r
+        {\r
+            Assert.True(GetDeltaApi.EndGenDeltaSession(), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void SdbPush(string caller_trace, string hostFullPath, string targetPath)\r
+        {\r
+            System.Diagnostics.Process process = new System.Diagnostics.Process();\r
+            process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;\r
+            process.StartInfo.RedirectStandardInput = true;\r
+            process.StartInfo.RedirectStandardOutput = true;\r
+            process.StartInfo.CreateNoWindow = true;\r
+            process.StartInfo.UseShellExecute = false;\r
+            \r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+            {\r
+                process.StartInfo.FileName = "bash";\r
+                process.StartInfo.Arguments = "-c \"sdb push " + hostFullPath + " " + targetPath + "\"";\r
+            }\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            process.Start();\r
+            process.WaitForExit();\r
+            Assert.Equal(0, process.ExitCode, @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void WriteDeltas(string caller_trace, string fileName)\r
+        {\r
+            string hostPath;\r
+            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))\r
+                hostPath = Path.Combine(@"/tmp", fileName);\r
+            else\r
+                throw new Exception("Host OS not supported. " + @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+\r
+            string targetPath = @"/tmp";\r
+            Assert.True(GetDeltaApi.WriteDeltas(hostPath), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".metadata", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".il", targetPath);\r
+            SdbPush(@"__FILE__:__LINE__"+"\n"+caller_trace, hostPath + ".pdb", targetPath);\r
+        }\r
+\r
+        public void GetDelta(string caller_trace, string source, string sourceFileName)\r
+        {\r
+            Assert.True(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void ErrorGetDelta(string caller_trace, string source, string sourceFileName)\r
+        {\r
+            Assert.False(GetDeltaApi.GetDeltas(source, sourceFileName, "", false), @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public void ApplyDeltas(string caller_trace, string fileName)\r
+        {\r
+            string targetPath = Path.Combine(@"/tmp", fileName);\r
+            string targetAssemblyName = Path.GetFileName(ControlInfo.TargetAssemblyPath);\r
+            Assert.Equal(MIResultClass.Done,\r
+                         MIDebugger.Request("-apply-deltas " + targetAssemblyName + " " + targetPath + ".metadata " + targetPath + ".il " + targetPath + ".pdb").Class,\r
+                         @"__FILE__:__LINE__"+"\n"+caller_trace);\r
+        }\r
+\r
+        public Context(ControlInfo controlInfo, NetcoreDbgTestCore.DebuggerClient debuggerClient)\r
+        {\r
+            ControlInfo = controlInfo;\r
+            MIDebugger = new MIDebugger(debuggerClient);\r
+            GetDeltaApi = new GetDeltaApi.GetDeltaApi();\r
+        }\r
+\r
+        ControlInfo ControlInfo;\r
+        MIDebugger MIDebugger;\r
+        GetDeltaApi.GetDeltaApi GetDeltaApi;\r
+    }\r
+}\r
+\r
+namespace MITestHotReloadWithoutBreak\r
+{\r
+    class Program\r
+    {\r
+        static void Main(string[] args)\r
+        {\r
+            Label.Checkpoint("init", "apply_test1", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.CheckHostRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.CheckHostOS(@"__FILE__:__LINE__");\r
+                Context.Prepare(@"__FILE__:__LINE__");\r
+                Context.WasEntryPointHit("TestAppHotReload", @"__FILE__:__LINE__");\r
+                // Note, target Hot Reload check must be after debuggee process start and stop at entry breakpoint.\r
+                Context.CheckTargetRuntimeVersion(@"__FILE__:__LINE__");\r
+                Context.StartGenDeltaSession(@"__FILE__:__LINE__");\r
+\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System; using System.Threading;\r
+                namespace TestAppHotReload\r
+                {\r
+                    class Program\r
+                    {\r
+                        static void Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World! Main updated."");\r
+                            HotReloadTest();\r
+                        }\r
+                        static void HotReloadTest()\r
+                        {\r
+                            int count = 0;\r
+                            while (count < 20)\r
+                            {\r
+                                HotReloadBreakpointTest1();\r
+                                System.Threading.Thread.Sleep(1000);\r
+                                count++;\r
+                            }\r
+                        }\r
+                        static void HotReloadBreakpointTest1()\r
+                        {\r
+                            Console.WriteLine(""Added string."");\r
+                        }\r
+                    }\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta1");\r
+\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("apply_test1", "apply_test2", (Object context) => {\r
+                Context Context = (Context)context;\r
+\r
+                System.Threading.Thread.Sleep(2000);\r
+\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System; using System.Diagnostics; using System.Threading;\r
+                namespace TestAppHotReload\r
+                {\r
+                    class Program\r
+                    {\r
+                        static void Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World! Main updated."");\r
+                            HotReloadTest();\r
+                        }\r
+                        static void HotReloadTest()\r
+                        {\r
+                            Console.WriteLine(""Updated string."");\r
+                            int count = 0;\r
+                            while (count < 20)\r
+                            {\r
+                                HotReloadBreakpointTest1();\r
+                                System.Threading.Thread.Sleep(1000);\r
+                                count++;\r
+                            }\r
+                        }\r
+                        static void HotReloadBreakpointTest1()\r
+                        {\r
+                            Console.WriteLine(""Updated string."");\r
+                            Debugger.Break();                                                           // line 25\r
+                        }\r
+                    }\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta2");\r
+            });\r
+\r
+            Label.Checkpoint("apply_test2", "finish", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.WasBreakHit(@"__FILE__:__LINE__", @"Program.cs", 25);\r
+\r
+                Context.GetDelta(@"__FILE__:__LINE__",\r
+                @"using System; using System.Threading;\r
+                namespace TestAppHotReload\r
+                {\r
+                    class Program\r
+                    {\r
+                        static void Main(string[] args)\r
+                        {\r
+                            Console.WriteLine(""Hello World! Main updated."");\r
+                            HotReloadTest();\r
+                        }\r
+                        static void HotReloadTest()\r
+                        {\r
+                            int count = 0;\r
+                            while (count < 20)\r
+                            {\r
+                                HotReloadBreakpointTest1();\r
+                                System.Threading.Thread.Sleep(1000);\r
+                                count++;\r
+                            }\r
+                        }\r
+                        static void HotReloadBreakpointTest1()\r
+                        {\r
+                            Console.WriteLine(""Removed lines..."");\r
+                        }\r
+                    }\r
+                }", @"Program.cs");\r
+                Context.WriteDeltas(@"__FILE__:__LINE__", "tmp_delta3");\r
+                Context.ApplyDeltas(@"__FILE__:__LINE__", "tmp_delta3");\r
+\r
+                Context.Continue(@"__FILE__:__LINE__");\r
+            });\r
+\r
+            Label.Checkpoint("finish", "", (Object context) => {\r
+                Context Context = (Context)context;\r
+                Context.EndGenDeltaSession(@"__FILE__:__LINE__");\r
+                Context.WasExit(@"__FILE__:__LINE__");\r
+                Context.DebuggerExit(@"__FILE__:__LINE__");\r
+            });\r
+        }\r
+    }\r
+}\r
index a32e12902a2ba21d70b27e46ab8a72f288eceb82..9b3a89f1e62acdca9f38325ab795375f3f3fa37c 100644 (file)
@@ -1,4 +1,4 @@
-using System;\r
+using System;using System.Diagnostics;using System.Threading;\r
                 namespace TestAppHotReload\r
                 {\r
                     class Program\r
diff --git a/test-suite/TestAppHotReloadAsync/Program.cs b/test-suite/TestAppHotReloadAsync/Program.cs
new file mode 100644 (file)
index 0000000..7013ea8
--- /dev/null
@@ -0,0 +1,18 @@
+using System;\r
+using System.Threading.Tasks;\r
+                namespace TestAppHotReloadAsync\r
+                {\r
+                    class Program\r
+                    {\r
+                        static async Task Main(string[] args)\r
+                        {\r
+                            Console.WriteLine("Hello World!");\r
+                            await HotReloadTestAsync();\r
+                        }\r
+                        static async Task HotReloadTestAsync()\r
+                        {\r
+                            Console.WriteLine("Initial string.");\r
+                            await Task.Delay(100);\r
+                        }\r
+                    }\r
+                }\r
diff --git a/test-suite/TestAppHotReloadAsync/TestAppHotReloadAsync.csproj b/test-suite/TestAppHotReloadAsync/TestAppHotReloadAsync.csproj
new file mode 100644 (file)
index 0000000..d453e9a
--- /dev/null
@@ -0,0 +1,8 @@
+<Project Sdk="Microsoft.NET.Sdk">\r
+\r
+  <PropertyGroup>\r
+    <OutputType>Exe</OutputType>\r
+    <TargetFramework>netcoreapp3.1</TargetFramework>\r
+  </PropertyGroup>\r
+\r
+</Project>\r
index 89cb055237207558c92fed87a6cd203ab69692e7..7e73045cd749e81c51e5c261491946664ad80cfa 100755 (executable)
@@ -57,7 +57,13 @@ ALL_TEST_NAMES=(
     "MITestNoJMCExceptionBreakpoint"
     "MITestSizeof"
     "MITestAsyncLambdaEvaluate"
+    "MITestHotReloadAsyncStepping"
+    "MITestHotReloadBreak"
     "MITestHotReloadBreakpoint"
+    "MITestHotReloadEvaluate"
+    "MITestHotReloadStepping"
+    "MITestHotReloadJMC"
+    "MITestHotReloadWithoutBreak"
     "VSCodeExampleTest"
     "VSCodeTestBreakpoint"
     "VSCodeTestFuncBreak"
@@ -202,7 +208,11 @@ for i in $(eval echo {1..$REPEAT}); do
 # Build, push and run tests
 for TEST_NAME in $TEST_NAMES; do
     TEST_PROJ_NAME=$TEST_NAME;
-    if  [[ $TEST_NAME == MITestHotReload* ]] ;
+
+    if  [[ $TEST_NAME == MITestHotReloadAsyncStepping ]] ;
+    then
+        TEST_PROJ_NAME="TestAppHotReloadAsync"
+    elif  [[ $TEST_NAME == MITestHotReload* ]] ;
     then
         TEST_PROJ_NAME="TestAppHotReload"
     fi