{"action":"opened","issue":{"url":"https://api.github.com/repos/dennisdoomen/fluentassertions/issues/305","labels_url":"https://api.github.com/repos/dennisdoomen/fluentassertions/issues/305/labels{/name}","comments_url":"https://api.github.com/repos/dennisdoomen/fluentassertions/issues/305/comments","events_url":"https://api.github.com/repos/dennisdoomen/fluentassertions/issues/305/events","html_url":"https://github.com/dennisdoomen/fluentassertions/issues/305","id":113508317,"number":305,"title":"ShouldBeEquivalentTo fails when comparing objects from the System namespace","user":{"login":"ConradLang","id":532578,"avatar_url":"https://avatars.githubusercontent.com/u/532578?v=3","gravatar_id":"","url":"https://api.github.com/users/ConradLang","html_url":"https://github.com/ConradLang","followers_url":"https://api.github.com/users/ConradLang/followers","following_url":"https://api.github.com/users/ConradLang/following{/other_user}","gists_url":"https://api.github.com/users/ConradLang/gists{/gist_id}","starred_url":"https://api.github.com/users/ConradLang/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ConradLang/subscriptions","organizations_url":"https://api.github.com/users/ConradLang/orgs","repos_url":"https://api.github.com/users/ConradLang/repos","events_url":"https://api.github.com/users/ConradLang/events{/privacy}","received_events_url":"https://api.github.com/users/ConradLang/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-10-27T05:16:01Z","updated_at":"2015-10-27T05:16:01Z","closed_at":null,"body":"Hi\r\n\r\nI'm using the expected object pattern to assert that the exception thrown is equivalent to the expected exception.\r\nIt appears that ShouldBeEquivalentTo works for objects outside the `System` namespace but not for objects in the `System` namespace.\r\nThis behaviour feels inconsistent - is it a bug?\r\n\r\nHere are three examples which can be used to reproduce the error.\r\n\r\n**1. The following snippet shows an example class defined in the `System` namespace and a `NotSystem` namespace and a couple of tests to show the unexpected failure when the class is defined in the system namespace.**\r\n\r\nI've created classes in the `System` namespace to show that it appears the issue is specific to when the class is in the `System` namespace.\r\n\r\n```c#\r\nnamespace System\r\n{\r\n    public class Something\r\n    {\r\n        public string TestValue => \"Something in System namespace\";\r\n    }\r\n}\r\n\r\nnamespace NotSystem\r\n{\r\n    public class Something\r\n    {\r\n        public string TestValue => \"Something not in System namespace\";\r\n    }\r\n}\r\n\r\nnamespace FluentValidationTests\r\n{\r\n    [TestClass]\r\n    public class UnitTest\r\n    {\r\n        [TestMethod]\r\n        public void ShouldBeEquivalentTo_With_Object_From_System_Namespace_Should_Pass()\r\n        {\r\n            var systemObject1 = new System.Something();\r\n            var systemObject2 = new System.Something();\r\n\r\n            // This fails because the \"Something\" class is in the \"System\" namespace.\r\n            systemObject2.ShouldBeEquivalentTo(systemObject1);\r\n        }\r\n\r\n        [TestMethod]\r\n        public void ShouldBeEquivalentTo_With_Object_From_Non_System_Namespace_Should_Pass()\r\n        {\r\n            var systemObject1 = new NotSystem.Something();\r\n            var systemObject2 = new NotSystem.Something();\r\n\r\n            // This passes because the \"Something\" class is _not_ in the \"System\" namespace.\r\n            systemObject2.ShouldBeEquivalentTo(systemObject1);\r\n        }\r\n    }\r\n}\r\n\r\n```\r\n\r\n*The `ShouldBeEquivalentTo_With_Object_From_System_Namespace_Should_Pass` test fails with:*\r\n```\r\nTest Name:  ShouldBeEquivalentTo_With_Object_From_System_Namespace_Should_Pass\r\nTest FullName:  FluentValidationTests.UnitTest.ShouldBeEquivalentTo_With_Object_From_System_Namespace_Should_Pass\r\nTest Source:    C:\\Projects\\TestFluentValidation\\FluentValidationTests\\UnitTest.cs : line 105\r\nTest Outcome:   Failed\r\nTest Duration:  0:00:00.0147143\r\n\r\nResult StackTrace:  \r\nat FluentAssertions.Execution.LateBoundTestFramework.Throw(String message) in C:\\projects\\fluentassertions-vf06b\\Src\\Shared\\Execution\\LateBoundTestFramework.cs:line 26\r\n   at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message) in C:\\projects\\fluentassertions-vf06b\\Src\\FluentAssertions.Net40\\Execution\\TestFrameworkProvider.cs:line 42\r\n   at FluentAssertions.Execution.CollectingAssertionStrategy.ThrowIfAny(IDictionary`2 context) in C:\\projects\\fluentassertions-vf06b\\Src\\Core\\Execution\\CollectingAssertionStrategy.cs:line 50\r\n   at FluentAssertions.Execution.AssertionScope.Dispose() in C:\\projects\\fluentassertions-vf06b\\Src\\Core\\Execution\\AssertionScope.cs:line 252\r\n   at FluentAssertions.Equivalency.EquivalencyValidator.AssertEquality(EquivalencyValidationContext context) in C:\\projects\\fluentassertions-vf06b\\Src\\Core\\Equivalency\\EquivalencyValidator.cs:line 37\r\n   at FluentAssertions.AssertionExtensions.ShouldBeEquivalentTo[T](T subject, Object expectation, Func`2 config, String because, Object[] reasonArgs) in C:\\projects\\fluentassertions-vf06b\\Src\\Shared\\AssertionExtensions.cs:line 610\r\n   at FluentAssertions.AssertionExtensions.ShouldBeEquivalentTo[T](T subject, Object expectation, String because, Object[] reasonArgs) in C:\\projects\\fluentassertions-vf06b\\Src\\Shared\\AssertionExtensions.cs:line 572\r\n   at FluentValidationTests.UnitTest.ShouldBeEquivalentTo_With_Object_From_System_Namespace_Should_Pass() in C:\\Projects\\TestFluentValidation\\FluentValidationTests\\UnitTest.cs:line 109\r\nResult Message: \r\nExpected subject to be \r\n\r\nSystem.Something\r\n{\r\n   TestValue = \"Something in System namespace\"\r\n}, but found \r\n\r\nSystem.Something\r\n{\r\n   TestValue = \"Something in System namespace\"\r\n}.\r\n\r\nWith configuration:\r\n- Use declared types and members\r\n- Compare enums by value\r\n- Match member by name (or throw)\r\n- Be strict about the order of items in byte arrays\r\n\r\n```\r\n\r\n**2. The following snippet shows an example custom exception class defined in the `System` namespace and a `NotSystem` namespace and a couple of tests to show the unexpected failure when the class is defined in the system namespace.**\r\n\r\n```c#\r\nnamespace System\r\n{\r\n    public class CustomException : System.Exception\r\n    {\r\n        public CustomException(string message) : base(message) { }\r\n    }\r\n}\r\n\r\nnamespace NotSystem\r\n{\r\n    public class CustomException : System.Exception\r\n    {\r\n        public CustomException(string message) : base(message) { }\r\n    }\r\n}\r\n\r\nnamespace FluentValidationTests\r\n{\r\n    [TestClass]\r\n    public class UnitTest\r\n    {\r\n        [TestMethod]\r\n        public void ShouldBeEquivalentTo_With_Custom_Exception_In_System_Namespace_Should_Pass()\r\n        {\r\n            var systemObject1 = new System.CustomException(\"A custom exception\");\r\n            System.CustomException systemObject2;\r\n            try\r\n            {\r\n                throw new System.CustomException(\"A custom exception\");\r\n            }\r\n            catch (System.CustomException ex)\r\n            {\r\n                systemObject2 = ex;\r\n            }\r\n\r\n            // Exclude non-public properties and properties that depend on where the exception is thrown.\r\n            var propertiesToExclude = typeof (System.CustomException).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic).Select(p => p.Name).ToList();\r\n            propertiesToExclude.Add(nameof(System.Exception.Source));\r\n            propertiesToExclude.Add(nameof(System.Exception.StackTrace));\r\n            propertiesToExclude.Add(nameof(System.Exception.TargetSite));\r\n\r\n            // This fails because the \"CustomException\" class is in the \"System\" namespace.\r\n            systemObject2.ShouldBeEquivalentTo(\r\n                systemObject1,\r\n                options => options.Excluding(ex => propertiesToExclude.Contains(ex.SelectedMemberInfo.Name)));\r\n        }\r\n\r\n        [TestMethod]\r\n        public void ShouldBeEquivalentTo_With_Custom_Exception_In_Non_System_Namespace_Should_Pass()\r\n        {\r\n            var systemObject1 = new NotSystem.CustomException(\"A custom exception\");\r\n            NotSystem.CustomException systemObject2;\r\n            try\r\n            {\r\n                throw new NotSystem.CustomException(\"A custom exception\");\r\n            }\r\n            catch (NotSystem.CustomException ex)\r\n            {\r\n                systemObject2 = ex;\r\n            }\r\n\r\n            // Exclude non-public properties and properties that depend on where the exception is thrown.\r\n            var propertiesToExclude = typeof (NotSystem.CustomException).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic).Select(p => p.Name).ToList();\r\n            propertiesToExclude.Add(nameof(System.Exception.Source));\r\n            propertiesToExclude.Add(nameof(System.Exception.StackTrace));\r\n            propertiesToExclude.Add(nameof(System.Exception.TargetSite));\r\n\r\n            // This passes because the \"CustomException\" class is _not_ in the \"System\" namespace.\r\n            systemObject2.ShouldBeEquivalentTo(\r\n                systemObject1,\r\n                options => options.Excluding(ex => propertiesToExclude.Contains(ex.SelectedMemberInfo.Name)));\r\n        }\r\n    }\r\n}\r\n```\r\n\r\n*The `ShouldBeEquivalentTo_With_Custom_Exception_In_System_Namespace_Should_Pass` test fails with:*\r\n```\r\nTest Name:  ShouldBeEquivalentTo_With_Custom_Exception_In_System_Namespace_Should_Pass\r\nTest FullName:  FluentValidationTests.UnitTest.ShouldBeEquivalentTo_With_Custom_Exception_In_System_Namespace_Should_Pass\r\nTest Source:    C:\\Projects\\TestFluentValidation\\FluentValidationTests\\UnitTest.cs : line 57\r\nTest Outcome:   Failed\r\nTest Duration:  0:00:00.0062068\r\n\r\nResult StackTrace:  \r\nat FluentAssertions.Execution.LateBoundTestFramework.Throw(String message) in C:\\projects\\fluentassertions-vf06b\\Src\\Shared\\Execution\\LateBoundTestFramework.cs:line 26\r\n   at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message) in C:\\projects\\fluentassertions-vf06b\\Src\\FluentAssertions.Net40\\Execution\\TestFrameworkProvider.cs:line 42\r\n   at FluentAssertions.Execution.CollectingAssertionStrategy.ThrowIfAny(IDictionary`2 context) in C:\\projects\\fluentassertions-vf06b\\Src\\Core\\Execution\\CollectingAssertionStrategy.cs:line 50\r\n   at FluentAssertions.Execution.AssertionScope.Dispose() in C:\\projects\\fluentassertions-vf06b\\Src\\Core\\Execution\\AssertionScope.cs:line 252\r\n   at FluentAssertions.Equivalency.EquivalencyValidator.AssertEquality(EquivalencyValidationContext context) in C:\\projects\\fluentassertions-vf06b\\Src\\Core\\Equivalency\\EquivalencyValidator.cs:line 37\r\n   at FluentAssertions.AssertionExtensions.ShouldBeEquivalentTo[T](T subject, Object expectation, Func`2 config, String because, Object[] reasonArgs) in C:\\projects\\fluentassertions-vf06b\\Src\\Shared\\AssertionExtensions.cs:line 610\r\n   at FluentValidationTests.UnitTest.ShouldBeEquivalentTo_With_Custom_Exception_In_System_Namespace_Should_Pass() in C:\\Projects\\TestFluentValidation\\FluentValidationTests\\UnitTest.cs:line 74\r\nResult Message: \r\nExpected subject to be System.CustomException with message \"A custom exception\"\r\n, but found System.CustomException with message \"A custom exception\"\r\n     at FluentValidationTests.UnitTest.ShouldBeEquivalentTo_With_Custom_Exception_In_System_Namespace_Should_Pass() in C:\\Projects\\TestFluentValidation\\FluentValidationTests\\UnitTest.cs:line 62\r\n.\r\n\r\nWith configuration:\r\n- Use declared types and members\r\n- Compare enums by value\r\n- Exclude member when value(FluentValidationTests.UnitTest+<>c__DisplayClass1_0).propertiesToExclude.Contains(ex.SelectedMemberInfo.Name)\r\n- Match member by name (or throw)\r\n- Be strict about the order of items in byte arrays\r\n```\r\n\r\n**3. The following snippet shows the behaviour when a `System.Exception` is compared.**\r\n\r\nThis shows that the .NET `System.Exception` (and any other system exception) is affected.\r\n\r\n```c#\r\nnamespace FluentValidationTests\r\n{\r\n    [TestClass]\r\n    public class UnitTest\r\n    {\r\n        [TestMethod]\r\n        public void ShouldBeEquivalentTo_With_System_Exception_Should_Pass()\r\n        {\r\n             var propertiesToExclude = typeof(System.Exception).GetProperties(BindingFlags.Instance | BindingFlags.NonPublic).Select(p => p.Name).ToList();\r\n            propertiesToExclude.Add(nameof(System.Exception.Source));\r\n            propertiesToExclude.Add(nameof(System.Exception.StackTrace));\r\n            propertiesToExclude.Add(nameof(System.Exception.TargetSite));\r\n\r\n            var systemObject1 = new System.Exception(\"Just a System.Exception\");\r\n            var systemObject2 = new System.Exception(\"Just a System.Exception\");\r\n\r\n            systemObject2.ShouldBeEquivalentTo(\r\n                systemObject1,\r\n                options => options.Excluding(ex => propertiesToExclude.Contains(ex.SelectedMemberInfo.Name)));\r\n       }\r\n    }\r\n}\r\n```\r\n\r\n*The test fails with:*\r\n```\r\nTest Name:  ShouldBeEquivalentTo_Should_Pass_With_System_Exceptions_But_Fails\r\nTest FullName:  FluentValidationTests.UnitTest.ShouldBeEquivalentTo_Should_Pass_With_System_Exceptions_But_Fails\r\nTest Source:    C:\\Projects\\TestFluentValidation\\FluentValidationTests\\UnitTest.cs : line 41\r\nTest Outcome:   Failed\r\nTest Duration:  0:00:00.3572282\r\n\r\nResult StackTrace:  \r\nat FluentAssertions.Execution.LateBoundTestFramework.Throw(String message) in C:\\projects\\fluentassertions-vf06b\\Src\\Shared\\Execution\\LateBoundTestFramework.cs:line 26\r\n   at FluentAssertions.Execution.TestFrameworkProvider.Throw(String message) in C:\\projects\\fluentassertions-vf06b\\Src\\FluentAssertions.Net40\\Execution\\TestFrameworkProvider.cs:line 42\r\n   at FluentAssertions.Execution.CollectingAssertionStrategy.ThrowIfAny(IDictionary`2 context) in C:\\projects\\fluentassertions-vf06b\\Src\\Core\\Execution\\CollectingAssertionStrategy.cs:line 50\r\n   at FluentAssertions.Execution.AssertionScope.Dispose() in C:\\projects\\fluentassertions-vf06b\\Src\\Core\\Execution\\AssertionScope.cs:line 252\r\n   at FluentAssertions.Equivalency.EquivalencyValidator.AssertEquality(EquivalencyValidationContext context) in C:\\projects\\fluentassertions-vf06b\\Src\\Core\\Equivalency\\EquivalencyValidator.cs:line 37\r\n   at FluentAssertions.AssertionExtensions.ShouldBeEquivalentTo[T](T subject, Object expectation, Func`2 config, String because, Object[] reasonArgs) in C:\\projects\\fluentassertions-vf06b\\Src\\Shared\\AssertionExtensions.cs:line 610\r\n   at FluentValidationTests.UnitTest.ShouldBeEquivalentTo_Should_Pass_With_System_Exceptions_But_Fails() in C:\\Projects\\TestFluentValidation\\FluentValidationTests\\UnitTest.cs:line 50\r\nResult Message: \r\nExpected subject to be System.Exception with message \"Just a System.Exception\"\r\n, but found System.Exception with message \"Just a System.Exception\"\r\n.\r\n\r\nWith configuration:\r\n- Use declared types and members\r\n- Compare enums by value\r\n- Exclude member when value(FluentValidationTests.UnitTest+<>c__DisplayClass0_0).propertiesToExclude.Contains(ex.SelectedMemberInfo.Name)\r\n- Match member by name (or throw)\r\n- Be strict about the order of items in byte arrays\r\n```"}}