From b8b3e59dfb4c687e38f581d2c596951b70adb361 Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 22 Oct 2021 13:29:26 -0300 Subject: [PATCH 1/5] Fix mono_get_generic_context_from_stack_frame when it's from a dim. --- src/mono/mono/mini/mini-exceptions.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mono/mono/mini/mini-exceptions.c b/src/mono/mono/mini/mini-exceptions.c index fa139ec666821..b251b83449af6 100644 --- a/src/mono/mono/mini/mini-exceptions.c +++ b/src/mono/mono/mini/mini-exceptions.c @@ -852,6 +852,9 @@ mono_get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_inf klass = vtable->klass; } + if (mono_class_is_interface (method->klass)) + return context; + //g_assert (!mono_class_is_gtd (method->klass)); if (mono_class_is_ginst (method->klass)) method_container_class = mono_class_get_generic_class (method->klass)->container_class; From f2007dc88e9da9ce28bc5dd7f9b9e332d21c3fd3 Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 22 Oct 2021 20:10:56 -0300 Subject: [PATCH 2/5] Using @vargaz fix --- src/mono/mono/mini/mini-exceptions.c | 14 ++-- .../regressions/github60486.csproj | 11 +++ .../regressions/githubs60486.cs | 77 +++++++++++++++++++ 3 files changed, 97 insertions(+), 5 deletions(-) create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.csproj create mode 100644 src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/githubs60486.cs diff --git a/src/mono/mono/mini/mini-exceptions.c b/src/mono/mono/mini/mini-exceptions.c index b251b83449af6..40f804499d0f2 100644 --- a/src/mono/mono/mini/mini-exceptions.c +++ b/src/mono/mono/mini/mini-exceptions.c @@ -840,27 +840,31 @@ mono_get_generic_context_from_stack_frame (MonoJitInfo *ji, gpointer generic_inf method = jinfo_get_method (ji); g_assert (method->is_inflated); - if (mono_method_get_context (method)->method_inst) { + if (mono_method_get_context (method)->method_inst || mini_method_is_default_method (method)) { MonoMethodRuntimeGenericContext *mrgctx = (MonoMethodRuntimeGenericContext *)generic_info; klass = mrgctx->class_vtable->klass; context.method_inst = mrgctx->method_inst; - g_assert (context.method_inst); + if (!mini_method_is_default_method (method)) + g_assert (context.method_inst); } else { MonoVTable *vtable = (MonoVTable *)generic_info; klass = vtable->klass; } - if (mono_class_is_interface (method->klass)) - return context; - //g_assert (!mono_class_is_gtd (method->klass)); if (mono_class_is_ginst (method->klass)) method_container_class = mono_class_get_generic_class (method->klass)->container_class; else method_container_class = method->klass; + if (mini_method_is_default_method (method)) { + if (mono_class_is_ginst (klass) || mono_class_is_gtd (klass)) + context.class_inst = mini_class_get_context (klass)->class_inst; + return context; + } + /* class might refer to a subclass of method's class */ while (!(klass == method->klass || (mono_class_is_ginst (klass) && mono_class_get_generic_class (klass)->container_class == method_container_class))) { klass = m_class_get_parent (klass); diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.csproj b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.csproj new file mode 100644 index 0000000000000..aab61d4e4497b --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.csproj @@ -0,0 +1,11 @@ + + + true + Exe + BuildAndRun + 0 + + + + + diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/githubs60486.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/githubs60486.cs new file mode 100644 index 0000000000000..2f837c8007db4 --- /dev/null +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/githubs60486.cs @@ -0,0 +1,77 @@ +using System; + +namespace CallingEnviromentStackTraceFromDim +{ + public interface IPublisher + { + event Action OnPublish; + } + + public interface ISubscriber + { + void OnReceiveSubscription(T data); + + void Subscribe(IPublisher publisher) + { + InternalSubscribe(this, publisher); + } + + void Unsubscribe(IPublisher publisher) + { + InternalUnsubscribe(this, publisher); + } + + protected static void InternalSubscribe(ISubscriber subscriber, IPublisher publisher) + { + publisher.OnPublish += subscriber.OnReceiveSubscription; + Console.WriteLine(Environment.StackTrace.ToString()); + } + + protected static void InternalUnsubscribe(ISubscriber subscriber, IPublisher publisher) + { + publisher.OnPublish -= subscriber.OnReceiveSubscription; + Console.WriteLine(Environment.StackTrace.ToString()); + } + } + + public class PubTest :IPublisher + { + public event Action OnPublish; + + public void Call() => OnPublish?.Invoke(new InputData()); + } + + public class InputData + { + public int i; + } + + public class Program : ISubscriber + { + static int Main() + { + new Program().Start(); + return 100; + } + + // Start is called before the first frame update + public void Start() + { + var pub = new PubTest(); + var sub = (ISubscriber)this; + sub.Subscribe(pub); + pub.Call(); + sub.Unsubscribe(pub); + } + + public void Subscribe(IPublisher publisher) + { + ISubscriber.InternalSubscribe(this, publisher); + } + + public void OnReceiveSubscription(InputData data) + { + Console.WriteLine($"do something"); + } + } +} \ No newline at end of file From e9eec2c20d11127f285618923742d6e074b81226 Mon Sep 17 00:00:00 2001 From: Thays Date: Fri, 22 Oct 2021 20:11:55 -0300 Subject: [PATCH 3/5] Fixing test case source name --- .../regressions/{githubs60486.cs => github60486.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/{githubs60486.cs => github60486.cs} (100%) diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/githubs60486.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.cs similarity index 100% rename from src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/githubs60486.cs rename to src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.cs From ee3654f8d42d33b284f100704f423b9f097b9f1f Mon Sep 17 00:00:00 2001 From: "DESKTOP-GEPIA6N\\Thays" Date: Fri, 26 Nov 2021 11:11:38 -0300 Subject: [PATCH 4/5] Fix behavior when the interface had static interface methods. --- src/mono/mono/metadata/object.c | 2 + .../regressions/github60486.cs | 190 +++++++++++++----- 2 files changed, 142 insertions(+), 50 deletions(-) diff --git a/src/mono/mono/metadata/object.c b/src/mono/mono/metadata/object.c index 70f77b0495c49..710bab5040bfb 100644 --- a/src/mono/mono/metadata/object.c +++ b/src/mono/mono/metadata/object.c @@ -1518,6 +1518,8 @@ build_imt_slots (MonoClass *klass, MonoVTable *vt, gpointer* imt, GSList *extra_ * add_imt_builder_entry anyway. */ method = mono_class_get_method_by_index (mono_class_get_generic_class (iface)->container_class, method_slot_in_interface); + if (m_method_is_static (method)) + continue; if (mono_method_get_imt_slot (method) != slot_num) { vt_slot ++; continue; diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.cs index 2f837c8007db4..4e793733f5f87 100644 --- a/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.cs +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.cs @@ -1,77 +1,167 @@ using System; -namespace CallingEnviromentStackTraceFromDim +public interface IPublisher { - public interface IPublisher + event Action OnPublish; +} + +public interface TestItf1 +{ + void TestMethod1(IPublisher publisher, StackFrame[] expectedFrames) { - event Action OnPublish; + StackFrame.Validate (Environment.StackTrace, expectedFrames); } - public interface ISubscriber + void TestMethod2(IPublisher publisher, StackFrame[] expectedFrames) { - void OnReceiveSubscription(T data); + TestMethod3 (this, publisher, expectedFrames); + } - void Subscribe(IPublisher publisher) - { - InternalSubscribe(this, publisher); - } + protected static void TestMethod3(TestItf1 subscriber, IPublisher publisher, StackFrame[] expectedFrames) + { + StackFrame.Validate (Environment.StackTrace, expectedFrames); + } - void Unsubscribe(IPublisher publisher) - { - InternalUnsubscribe(this, publisher); - } + void TestMethod4(IPublisher publisher, StackFrame[] expectedFrames) + { + TestMethod3 (this, publisher, expectedFrames); + } - protected static void InternalSubscribe(ISubscriber subscriber, IPublisher publisher) - { - publisher.OnPublish += subscriber.OnReceiveSubscription; - Console.WriteLine(Environment.StackTrace.ToString()); - } + void TestMethod5(IPublisher publisher, StackFrame[] expectedFrames) + { + TestMethod3 (this, publisher, expectedFrames); + } - protected static void InternalUnsubscribe(ISubscriber subscriber, IPublisher publisher) - { - publisher.OnPublish -= subscriber.OnReceiveSubscription; - Console.WriteLine(Environment.StackTrace.ToString()); - } + void TestMethod10(IPublisher publisher, StackFrame[] expectedFrames) + { + TestMethod3 (this, publisher, expectedFrames); } - public class PubTest :IPublisher + void TestMethod11(IPublisher publisher, StackFrame[] expectedFrames); +} + +public interface TestItf2 : TestItf1 +{ + void TestItf1.TestMethod5(IPublisher publisher, StackFrame[] expectedFrames) { - public event Action OnPublish; + TestMethod3 (this, publisher, expectedFrames); + } - public void Call() => OnPublish?.Invoke(new InputData()); + void TestItf1.TestMethod10(IPublisher publisher, StackFrame[] expectedFrames) + { + TestMethod3 (this, publisher, expectedFrames); } +} - public class InputData +public interface TestItf3 : TestItf1 +{ + void TestMethod6(IPublisher publisher, StackFrame[] expectedFrames) { - public int i; + TestMethod3 (this, publisher, expectedFrames); } - public class Program : ISubscriber + void TestMethod7(IPublisher publisher, StackFrame[] expectedFrames) { - static int Main() - { - new Program().Start(); - return 100; - } - - // Start is called before the first frame update - public void Start() - { - var pub = new PubTest(); - var sub = (ISubscriber)this; - sub.Subscribe(pub); - pub.Call(); - sub.Unsubscribe(pub); - } + TestMethod8 (this, publisher, expectedFrames); + } - public void Subscribe(IPublisher publisher) - { - ISubscriber.InternalSubscribe(this, publisher); - } + protected static void TestMethod8(TestItf1 subscriber, IPublisher publisher, StackFrame[] expectedFrames) + { + StackFrame.Validate (Environment.StackTrace, expectedFrames); + } + + void TestMethod9(IPublisher publisher, StackFrame[] expectedFrames); +} + +public interface TestItf4 : TestItf3 +{ + void TestItf3.TestMethod9(IPublisher publisher, StackFrame[] expectedFrames) + { + TestMethod8 (this, publisher, expectedFrames); + } +} + +public class ProgramBase : TestItf4 +{ + public void TestMethod10(IPublisher publisher, StackFrame[] expectedFrames) + { + TestItf1.TestMethod3 (this, publisher, expectedFrames); + } + + public void TestMethod11(IPublisher publisher, StackFrame[] expectedFrames) + { + TestItf1.TestMethod3 (this, publisher, expectedFrames); + } +} + +public class Program : ProgramBase, TestItf2 +{ + static int Main(string[] args) + { + new Program().Start(); + return 100; + } + + public void Start() + { + var t1 = this as TestItf1; + t1.TestMethod1(null, new [] {new StackFrame ("TestItf1`1", "TestMethod1")}); + t1.TestMethod2(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("TestItf1`1", "TestMethod2")}); + t1.TestMethod4(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("Program", "TestMethod4")}); + t1.TestMethod5(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("TestItf2`1.TestItf1", "TestMethod5")}); + + var t3 = this as TestItf3; + t3.TestMethod6(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("TestItf3`1", "TestMethod6")}); + t3.TestMethod7(null, new [] {new StackFrame ("TestItf3`1", "TestMethod8"), new StackFrame ("TestItf3`1", "TestMethod7")}); + t3.TestMethod9(null, new [] {new StackFrame ("TestItf3`1", "TestMethod8"), new StackFrame ("TestItf4`1.TestItf3", "TestMethod9")}); - public void OnReceiveSubscription(InputData data) + t1.TestMethod10(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("ProgramBase`1", "TestMethod10")}); + t1.TestMethod11(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("ProgramBase`1", "TestMethod11")}); + } + + public void TestMethod4(IPublisher publisher, StackFrame[] expectedFrames) + { + TestItf1.TestMethod3 (this, publisher, expectedFrames); + } +} + +public class InputData +{ + public int i; +} + +public class StackFrame +{ + public string ClassName {get; set;} = string.Empty; + public string MethodName {get; set;} = string.Empty; + + public StackFrame (string className, string methodName) + { + ClassName = className; + MethodName = methodName; + } + + public static void Validate (string testStack, StackFrame[] expectedFrames) + { + int index = 1; + + string[] lines = testStack.Split( + new string[] { Environment.NewLine }, + StringSplitOptions.None + ); + + //Console.WriteLine(testStack); + + foreach (var frame in expectedFrames) { - Console.WriteLine($"do something"); + var line = lines[index++].Trim(); + + if (!line.StartsWith ($"at {frame.ClassName}") || !line.Contains ($".{frame.MethodName}")) + { + Console.WriteLine ($"Expected {frame.ClassName}.{frame.MethodName} but got {line}"); + Console.WriteLine(testStack); + Environment.Exit (1); + } } } } \ No newline at end of file From 33ad356ebebdb4be07057d2f3bf4b112e6ab6866 Mon Sep 17 00:00:00 2001 From: "DESKTOP-GEPIA6N\\Thays" Date: Thu, 2 Dec 2021 11:05:04 -0300 Subject: [PATCH 5/5] Fixing test cases. --- .../regressions/github60486.cs | 85 ++++++++++++------- 1 file changed, 54 insertions(+), 31 deletions(-) diff --git a/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.cs b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.cs index 4e793733f5f87..f32ff4725d559 100644 --- a/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.cs +++ b/src/tests/Loader/classloader/DefaultInterfaceMethods/regressions/github60486.cs @@ -1,4 +1,5 @@ using System; +using System.Runtime.CompilerServices; public interface IPublisher { @@ -7,34 +8,40 @@ public interface IPublisher public interface TestItf1 { + [MethodImpl(MethodImplOptions.NoInlining)] void TestMethod1(IPublisher publisher, StackFrame[] expectedFrames) { - StackFrame.Validate (Environment.StackTrace, expectedFrames); + StackFrame.Validate(Environment.StackTrace, expectedFrames); } + [MethodImpl(MethodImplOptions.NoInlining)] void TestMethod2(IPublisher publisher, StackFrame[] expectedFrames) { - TestMethod3 (this, publisher, expectedFrames); + TestMethod3(this, publisher, expectedFrames); } + [MethodImpl(MethodImplOptions.NoInlining)] protected static void TestMethod3(TestItf1 subscriber, IPublisher publisher, StackFrame[] expectedFrames) { - StackFrame.Validate (Environment.StackTrace, expectedFrames); + StackFrame.Validate(Environment.StackTrace, expectedFrames); } + [MethodImpl(MethodImplOptions.NoInlining)] void TestMethod4(IPublisher publisher, StackFrame[] expectedFrames) { - TestMethod3 (this, publisher, expectedFrames); + TestMethod3(this, publisher, expectedFrames); } + [MethodImpl(MethodImplOptions.NoInlining)] void TestMethod5(IPublisher publisher, StackFrame[] expectedFrames) { - TestMethod3 (this, publisher, expectedFrames); + TestMethod3(this, publisher, expectedFrames); } + [MethodImpl(MethodImplOptions.NoInlining)] void TestMethod10(IPublisher publisher, StackFrame[] expectedFrames) { - TestMethod3 (this, publisher, expectedFrames); + TestMethod3(this, publisher, expectedFrames); } void TestMethod11(IPublisher publisher, StackFrame[] expectedFrames); @@ -42,32 +49,37 @@ void TestMethod10(IPublisher publisher, StackFrame[] expectedFrames) public interface TestItf2 : TestItf1 { + [MethodImpl(MethodImplOptions.NoInlining)] void TestItf1.TestMethod5(IPublisher publisher, StackFrame[] expectedFrames) { - TestMethod3 (this, publisher, expectedFrames); + TestMethod3(this, publisher, expectedFrames); } + [MethodImpl(MethodImplOptions.NoInlining)] void TestItf1.TestMethod10(IPublisher publisher, StackFrame[] expectedFrames) { - TestMethod3 (this, publisher, expectedFrames); + TestMethod3(this, publisher, expectedFrames); } } public interface TestItf3 : TestItf1 { + [MethodImpl(MethodImplOptions.NoInlining)] void TestMethod6(IPublisher publisher, StackFrame[] expectedFrames) { - TestMethod3 (this, publisher, expectedFrames); + TestMethod3(this, publisher, expectedFrames); } + [MethodImpl(MethodImplOptions.NoInlining)] void TestMethod7(IPublisher publisher, StackFrame[] expectedFrames) { - TestMethod8 (this, publisher, expectedFrames); + TestMethod8(this, publisher, expectedFrames); } + [MethodImpl(MethodImplOptions.NoInlining)] protected static void TestMethod8(TestItf1 subscriber, IPublisher publisher, StackFrame[] expectedFrames) { - StackFrame.Validate (Environment.StackTrace, expectedFrames); + StackFrame.Validate(Environment.StackTrace, expectedFrames); } void TestMethod9(IPublisher publisher, StackFrame[] expectedFrames); @@ -75,22 +87,25 @@ protected static void TestMethod8(TestItf1 subscriber, IPublisher publis public interface TestItf4 : TestItf3 { + [MethodImpl(MethodImplOptions.NoInlining)] void TestItf3.TestMethod9(IPublisher publisher, StackFrame[] expectedFrames) { - TestMethod8 (this, publisher, expectedFrames); + TestMethod8(this, publisher, expectedFrames); } } public class ProgramBase : TestItf4 { + [MethodImpl(MethodImplOptions.NoInlining)] public void TestMethod10(IPublisher publisher, StackFrame[] expectedFrames) { - TestItf1.TestMethod3 (this, publisher, expectedFrames); + TestItf1.TestMethod3(this, publisher, expectedFrames); } + [MethodImpl(MethodImplOptions.NoInlining)] public void TestMethod11(IPublisher publisher, StackFrame[] expectedFrames) { - TestItf1.TestMethod3 (this, publisher, expectedFrames); + TestItf1.TestMethod3(this, publisher, expectedFrames); } } @@ -105,23 +120,24 @@ static int Main(string[] args) public void Start() { var t1 = this as TestItf1; - t1.TestMethod1(null, new [] {new StackFrame ("TestItf1`1", "TestMethod1")}); - t1.TestMethod2(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("TestItf1`1", "TestMethod2")}); - t1.TestMethod4(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("Program", "TestMethod4")}); - t1.TestMethod5(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("TestItf2`1.TestItf1", "TestMethod5")}); + t1.TestMethod1(null, new[] { new StackFrame("TestItf1`1", "TestMethod1") }); + t1.TestMethod2(null, new[] { new StackFrame("TestItf1`1", "TestMethod3"), new StackFrame("TestItf1`1", "TestMethod2") }); + t1.TestMethod4(null, new[] { new StackFrame("TestItf1`1", "TestMethod3"), new StackFrame("Program", "TestMethod4") }); + t1.TestMethod5(null, new[] { new StackFrame("TestItf1`1", "TestMethod3"), new StackFrame(new[] { "TestItf2`1", "TestItf1" }, "TestMethod5") }); var t3 = this as TestItf3; - t3.TestMethod6(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("TestItf3`1", "TestMethod6")}); - t3.TestMethod7(null, new [] {new StackFrame ("TestItf3`1", "TestMethod8"), new StackFrame ("TestItf3`1", "TestMethod7")}); - t3.TestMethod9(null, new [] {new StackFrame ("TestItf3`1", "TestMethod8"), new StackFrame ("TestItf4`1.TestItf3", "TestMethod9")}); + t3.TestMethod6(null, new[] { new StackFrame("TestItf1`1", "TestMethod3"), new StackFrame("TestItf3`1", "TestMethod6") }); + t3.TestMethod7(null, new[] { new StackFrame("TestItf3`1", "TestMethod8"), new StackFrame("TestItf3`1", "TestMethod7") }); + t3.TestMethod9(null, new[] { new StackFrame("TestItf3`1", "TestMethod8"), new StackFrame(new[] { "TestItf4`1", "TestItf3" }, "TestMethod9") }); - t1.TestMethod10(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("ProgramBase`1", "TestMethod10")}); - t1.TestMethod11(null, new [] {new StackFrame ("TestItf1`1", "TestMethod3"), new StackFrame ("ProgramBase`1", "TestMethod11")}); + t1.TestMethod10(null, new[] { new StackFrame("TestItf1`1", "TestMethod3"), new StackFrame("ProgramBase`1", "TestMethod10") }); + t1.TestMethod11(null, new[] { new StackFrame("TestItf1`1", "TestMethod3"), new StackFrame("ProgramBase`1", "TestMethod11") }); } + [MethodImpl(MethodImplOptions.NoInlining)] public void TestMethod4(IPublisher publisher, StackFrame[] expectedFrames) { - TestItf1.TestMethod3 (this, publisher, expectedFrames); + TestItf1.TestMethod3(this, publisher, expectedFrames); } } @@ -132,16 +148,22 @@ public class InputData public class StackFrame { - public string ClassName {get; set;} = string.Empty; - public string MethodName {get; set;} = string.Empty; + public string [] ClassName { get; set; } + public string MethodName { get; set; } = string.Empty; - public StackFrame (string className, string methodName) + public StackFrame(string [] className, string methodName) { ClassName = className; MethodName = methodName; } - public static void Validate (string testStack, StackFrame[] expectedFrames) + public StackFrame(string className, string methodName) + { + ClassName = new string[] { className }; + MethodName = methodName; + } + + public static void Validate(string testStack, StackFrame[] expectedFrames) { int index = 1; @@ -156,11 +178,12 @@ public static void Validate (string testStack, StackFrame[] expectedFrames) { var line = lines[index++].Trim(); - if (!line.StartsWith ($"at {frame.ClassName}") || !line.Contains ($".{frame.MethodName}")) + + if (!line.StartsWith($"at {frame.ClassName[0]}") || !line.Contains($".{frame.MethodName}") || (frame.ClassName.Length > 1 && !line.Contains($".{frame.ClassName[1]}"))) { - Console.WriteLine ($"Expected {frame.ClassName}.{frame.MethodName} but got {line}"); + Console.WriteLine($"Expected {frame.ClassName}.{frame.MethodName} but got {line}"); Console.WriteLine(testStack); - Environment.Exit (1); + Environment.Exit(1); } } }