public void DestructuringDepthIsLimitedByConfiguredDepth()
        {
            // Arrange
            var exception = new RecursiveException()
            {
                Node = new RecursiveNode()
                {
                    Name  = "PARENT",
                    Child = new RecursiveNode()
                    {
                        Name  = "CHILD 1",
                        Child = new RecursiveNode()
                        {
                            Name = "CHILD 2",
                        },
                    },
                },
            };
            var destructurer = new ReflectionBasedDestructurer(1);

            // Act
            var propertiesBag = new ExceptionPropertiesBag(exception);

            destructurer.Destructure(exception, propertiesBag, EmptyDestructurer());

            // Assert
            // Parent is depth 1
            // First child is depth 2
            var properties = propertiesBag.GetResultDictionary();
            var parent     = (IDictionary <string, object>)properties[nameof(RecursiveException.Node)];

            Assert.Equal("PARENT", parent[nameof(RecursiveNode.Name)]);
            Assert.IsType <RecursiveNode>(parent[nameof(RecursiveNode.Child)]);
        }
        public async Task CanDestructureTaskAsync()
        {
            using var cancellationTokenSource = new CancellationTokenSource(0);

            TaskCanceledException exception = null;

            try
            {
                await Task.Delay(1000, cancellationTokenSource.Token).ConfigureAwait(false);
            }
            catch (TaskCanceledException taskCancelledException)
            {
                exception = taskCancelledException;
            }

            var propertiesBag = new ExceptionPropertiesBag(exception);

            CreateReflectionBasedDestructurer().Destructure(exception, propertiesBag, EmptyDestructurer());

            var properties                 = propertiesBag.GetResultDictionary();
            var destructuredTaskObject     = (IDictionary)properties[nameof(TaskCanceledException.Task)];
            var destructuredTaskProperties = Assert.IsAssignableFrom <IDictionary <string, object> >(destructuredTaskObject);

            destructuredTaskProperties.Should().ContainKey(nameof(Task.Id));
            destructuredTaskProperties.Should().ContainKey(nameof(Task.Status))
            .WhichValue.Should().BeOfType <string>()
            .Which.Should().Be(nameof(TaskStatus.Canceled));
            destructuredTaskProperties.Should().ContainKey(nameof(Task.CreationOptions))
            .WhichValue.Should().BeOfType <string>()
            .Which.Should().Contain(nameof(TaskCreationOptions.None));
        }
        public void WhenObjectContainsCyclicReferencesInList_ThenRecursiveDestructureIsImmediatelyStopped()
        {
            // Arrange
            var cyclic = new MyObjectCollection
            {
                Foo = "Cyclic",
            };

            cyclic.Reference = cyclic;
            var exception = new Cyclic2Exception
            {
                MyObjectCollection = new MyObjectCollection(),
            };

            exception.MyObjectCollection.Foo       = "bar";
            exception.MyObjectCollection.Reference = cyclic;

            // Act
            var result       = new ExceptionPropertiesBag(new Exception());
            var destructurer = new ReflectionBasedDestructurer(10);

            destructurer.Destructure(exception, result, EmptyDestructurer());

            // Assert
            var myObject = (List <object>)result.GetResultDictionary()[nameof(Cyclic2Exception.MyObjectCollection)];

            // exception.MyObjectCollection[0] is still list
            var firstLevelList = Assert.IsType <List <object> >(myObject[0]);

            // exception.MyObjectCollection[0][0] we notice that we would again destructure "cyclic"
            var secondLevelList = Assert.IsType <Dictionary <string, object> >(firstLevelList[0]);

            Assert.Equal("Cyclic reference", secondLevelList["$ref"]);
        }
Example #4
0
        // To be discussed: whether we need to keep consistent behaviour even for inner exceptions
        //[Fact]
        //public void WhenDestruringAggregateException_ResultShouldBeEquivalentToAggregateExceptionDestructurer()
        //{
        //    var argumentException = ThrowAndCatchException(() => throw new ArgumentException("MESSAGE", "paramName"));
        //    var aggregateException = ThrowAndCatchException(() => throw new AggregateException(argumentException));
        //    Test_ResultOfReflectionDestructurerShouldBeEquivalentToCustomOne(aggregateException, new AggregateExceptionDestructurer());
        //}

        private static void Test_ResultOfReflectionDestructurerShouldBeEquivalentToCustomOne(
            Exception exception,
            IExceptionDestructurer customDestructurer)
        {
            // Arrange
            var reflectionBasedResult       = new ExceptionPropertiesBag(exception);
            var customBasedResult           = new ExceptionPropertiesBag(exception);
            var reflectionBasedDestructurer = CreateReflectionBasedDestructurer();

            // Act
            Func <Exception, IReadOnlyDictionary <string, object> > InnerDestructure(IExceptionDestructurer destructurer)
            {
                return((ex) =>
                {
                    var resultsBag = new ExceptionPropertiesBag(ex);

                    destructurer.Destructure(ex, resultsBag, null);

                    return resultsBag.GetResultDictionary();
                });
            }

            reflectionBasedDestructurer.Destructure(exception, reflectionBasedResult, InnerDestructure(reflectionBasedDestructurer));
            customDestructurer.Destructure(exception, customBasedResult, InnerDestructure(new ArgumentExceptionDestructurer()));

            // Assert
            var reflectionBasedDictionary = (Dictionary <string, object>)reflectionBasedResult.GetResultDictionary();
            var customBasedDictionary     = (Dictionary <string, object>)customBasedResult.GetResultDictionary();

            reflectionBasedDictionary.Should().BeEquivalentTo(customBasedDictionary);
        }
        public void WhenObjectContainsCyclicReferencesInTask_ThenRecursiveDestructureIsImmediatelyStopped()
        {
            // Arrange
            var exception = new CyclicTaskException();
            var task      = Task.FromException(exception);

            exception.Task = task;

            // Act
            var result       = new ExceptionPropertiesBag(exception);
            var destructurer = CreateReflectionBasedDestructurer();

            destructurer.Destructure(exception, result, InnerDestructurer(destructurer));

            // Assert
            var resultsDictionary           = result.GetResultDictionary();
            var destructuredTask            = resultsDictionary[nameof(CyclicTaskException.Task)].Should().BeAssignableTo <IDictionary <string, object> >().Which;
            var destructuredCyclicException = destructuredTask.Should().ContainKey(nameof(Task.Exception))
                                              .WhichValue.Should().BeAssignableTo <IDictionary <string, object> >()
                                              .Which.Should().ContainKey(nameof(AggregateException.InnerExceptions))
                                              .WhichValue.Should().BeAssignableTo <IReadOnlyCollection <object> >()
                                              .Which.Should().ContainSingle()
                                              .Which.Should().BeAssignableTo <IDictionary <string, object> >().Which;

            destructuredCyclicException.Should().ContainKey(nameof(Exception.Message))
            .WhichValue.Should().BeOfType <string>()
            .Which.Should().Contain(nameof(CyclicTaskException));
            destructuredCyclicException.Should().ContainKey(nameof(CyclicTaskException.Task))
            .WhichValue.Should().BeAssignableTo <IDictionary <string, object> >()
            .Which.Should().ContainKey("$ref", "task was already destructured, so inner task should just contain ref");
        }
        public void DestructureComplexException_EachTypeOfPropertyIsDestructuredAsExpected()
        {
            // Arrange
            var exception     = ThrowAndCatchException(() => throw new TestException());
            var propertiesBag = new ExceptionPropertiesBag(exception);

            // Act
            CreateReflectionBasedDestructurer().Destructure(exception, propertiesBag, EmptyDestructurer());

            // Assert
            var properties = propertiesBag.GetResultDictionary();

            Assert.Equal("PublicValue", properties[nameof(TestException.PublicProperty)]);
            Assert.Equal("threw System.Exception: Exception of type 'System.Exception' was thrown.", properties[nameof(TestException.ExceptionProperty)]);
            Assert.DoesNotContain(properties, x => string.Equals(x.Key, "InternalProperty", StringComparison.Ordinal));
            Assert.DoesNotContain(properties, x => string.Equals(x.Key, "ProtectedProperty", StringComparison.Ordinal));
            Assert.DoesNotContain(properties, x => string.Equals(x.Key, "PrivateProperty", StringComparison.Ordinal));
            Assert.Equal("MessageValue", properties[nameof(TestException.Message)]);
#if NET461 || NET472
            Assert.StartsWith("Void DestructureComplexException_EachTypeOfPropertyIsDestructuredAsExpected(", properties[nameof(TestException.TargetSite)].ToString());
#endif
            Assert.NotEmpty(properties[nameof(TestException.StackTrace)].ToString());
            Assert.Equal("Serilog.Exceptions.Test", properties[nameof(TestException.Source)]);
            Assert.Equal(-2146233088, properties[nameof(TestException.HResult)]);
            Assert.Contains(typeof(TestException).FullName, properties["Type"].ToString(), StringComparison.Ordinal);
        }
        public void WhenObjectContainsCyclicReferences_ThenNoStackoverflowExceptionIsThrown()
        {
            // Arrange
            var exception = new CyclicException
            {
                MyObject = new MyObject(),
            };

            exception.MyObject.Foo        = "bar";
            exception.MyObject.Reference  = exception.MyObject;
            exception.MyObject.Reference2 = exception.MyObject;

            // Act
            var result       = new ExceptionPropertiesBag(new Exception());
            var destructurer = new ReflectionBasedDestructurer(10);

            destructurer.Destructure(exception, result, EmptyDestructurer());

            // Assert
            var myObject = (Dictionary <string, object>)result.GetResultDictionary()["MyObject"];

            Assert.Equal("bar", myObject["Foo"]);
            Assert.Equal(myObject["$id"], ((Dictionary <string, object>)myObject["Reference"])["$ref"]);
            Assert.Equal(myObject["$id"], ((Dictionary <string, object>)myObject["Reference2"])["$ref"]);
            Assert.Equal("1", myObject["$id"]);
        }
        private static Func <Exception, IReadOnlyDictionary <string, object> > InnerDestructurer(
            IExceptionDestructurer destructurer) =>
        (ex) =>
        {
            var resultsBag = new ExceptionPropertiesBag(ex);

            destructurer.Destructure(ex, resultsBag, InnerDestructurer(destructurer));

            return(resultsBag.GetResultDictionary());
        };
        public void CannotAddProperty_WhenResultWasAlreadyAquired()
        {
            // Arrange
            var properties = new ExceptionPropertiesBag(new Exception(), null);

            properties.AddProperty("key", "value");
            var results = properties.GetResultDictionary();

            // Act
            var ex = Assert.Throws <InvalidOperationException>(() => properties.AddProperty("key2", "value2"));

            // Assert
            Assert.Equal("Cannot add exception property 'key2' to bag, after results were already collected", ex.Message);
        }
        public void CanDestructureUriProperty()
        {
            const string uriValue  = "http://localhost/property";
            var          exception = new UriException("test", new Uri(uriValue));

            var propertiesBag = new ExceptionPropertiesBag(exception);

            CreateReflectionBasedDestructurer().Destructure(exception, propertiesBag, EmptyDestructurer());

            var properties       = propertiesBag.GetResultDictionary();
            var uriPropertyValue = properties[nameof(UriException.Uri)];

            Assert.IsType <string>(uriPropertyValue);
            Assert.Equal(uriValue, uriPropertyValue);
        }
        public void AddedProperty_WhenFilterIsSetToIgnoreIt_IsSkipped()
        {
            // Arrange
            var properties = new ExceptionPropertiesBag(
                new Exception(),
                new IgnorePropertyByNameExceptionFilter(new[] { "key" }));

            // Act
            properties.AddProperty("key", "value");

            // Assert
            var results = properties.GetResultDictionary();

            Assert.Equal(0, results.Count);
        }
        public void AddedProperty_IsAvailableInReturnedDictionary()
        {
            // Arrange
            var properties = new ExceptionPropertiesBag(new Exception(), null);

            // Act
            properties.AddProperty("key", "value");

            // Assert
            var results = properties.GetResultDictionary();

            Assert.Equal(1, results.Count);
            Assert.Contains("key", results.Keys);
            var value = results["key"];

            Assert.Equal("value", value);
        }
        private static void Test_ResultOfReflectionDestructurerShouldBeEquivalentToCustomOne(
            Exception exception,
            IExceptionDestructurer customDestructurer)
        {
            // Arrange
            var reflectionBasedResult       = new ExceptionPropertiesBag(exception);
            var customBasedResult           = new ExceptionPropertiesBag(exception);
            var reflectionBasedDestructurer = CreateReflectionBasedDestructurer();

            // Act
            reflectionBasedDestructurer.Destructure(exception, reflectionBasedResult, InnerDestructurer(reflectionBasedDestructurer));
            customDestructurer.Destructure(exception, customBasedResult, InnerDestructurer(new ArgumentExceptionDestructurer()));

            // Assert
            var reflectionBasedDictionary = (Dictionary <string, object>)reflectionBasedResult.GetResultDictionary();
            var customBasedDictionary     = (Dictionary <string, object>)customBasedResult.GetResultDictionary();

            reflectionBasedDictionary.Should().BeEquivalentTo(customBasedDictionary);
        }
        public void AddedProperty_WhenFilterIsNotSetToIgnoreIt_IsIncluded()
        {
            // Arrange
            var properties = new ExceptionPropertiesBag(
                new Exception(),
                new IgnorePropertyByNameExceptionFilter(new[] { "not key" }));

            // Act
            properties.AddProperty("key", "value");

            // Assert
            var results = properties.GetResultDictionary();

            Assert.Equal(1, results.Count);
            Assert.Contains("key", results.Keys);
            var value = results["key"];

            Assert.Equal("value", value);
        }
        public void CanDestructureObjectWithHiddenProperty()
        {
            var derived = new DerivedClass <int>
            {
                HiddenProperty = 123,
            };
            var baseClass = (BaseClass)derived;

            baseClass.HiddenProperty = 456;
            var exception = new HiddenException("test", derived);

            var propertiesBag = new ExceptionPropertiesBag(exception);

            CreateReflectionBasedDestructurer().Destructure(exception, propertiesBag, EmptyDestructurer());

            var properties = propertiesBag.GetResultDictionary();
            var info       = properties[nameof(HiddenException.Info)] as IDictionary <string, object>;

            Assert.Equal(derived.HiddenProperty, info[nameof(DerivedClass <object> .HiddenProperty)]);
            Assert.Equal(baseClass.HiddenProperty, info[$"{typeof(BaseClass).FullName}.{nameof(BaseClass.HiddenProperty)}"]);
        }
Example #16
0
        public void CanDestructureTask()
        {
            Task task      = new TaskFactory <int>().StartNew(() => 12, TaskCreationOptions.LongRunning | TaskCreationOptions.PreferFairness);
            var  exception = new TaskCanceledException(task);

            var propertiesBag = new ExceptionPropertiesBag(exception);

            CreateReflectionBasedDestructurer().Destructure(exception, propertiesBag, EmptyDestructurer());

            var properties                 = propertiesBag.GetResultDictionary();
            var destructuredTaskObject     = (IDictionary)properties[nameof(TaskCanceledException.Task)];
            var destructuredTaskProperties = Assert.IsAssignableFrom <IDictionary <string, object> >(destructuredTaskObject);

            destructuredTaskProperties.Should().ContainKey(nameof(Task.Id));
            destructuredTaskProperties.Should().ContainKey(nameof(Task.Status))
            .WhichValue.Should().BeOfType <string>()
            .Which.Should().Be(nameof(TaskStatus.RanToCompletion));
            destructuredTaskProperties.Should().ContainKey(nameof(Task.CreationOptions))
            .WhichValue.Should().BeOfType <string>()
            .Which.Should().Contain(nameof(TaskCreationOptions.LongRunning))
            .And.Contain(nameof(TaskCreationOptions.PreferFairness));
        }
        public void CanDestructureUriDataItem()
        {
            const string uriValue  = "http://localhost/data-item";
            var          exception = new Exception("test")
            {
                Data =
                {
                    { "UriDataItem", new Uri(uriValue) },
                },
            };

            var propertiesBag = new ExceptionPropertiesBag(exception);

            CreateReflectionBasedDestructurer().Destructure(exception, propertiesBag, EmptyDestructurer());

            var properties   = propertiesBag.GetResultDictionary();
            var data         = (IDictionary)properties[nameof(Exception.Data)];
            var uriDataValue = data["UriDataItem"];

            Assert.IsType <string>(uriDataValue);
            Assert.Equal(uriValue, uriDataValue);
        }
        public void CanDestructureStructDataItem()
        {
            // Arrange
            var exception = new Exception("test");

            exception.Data["data"] = new TestStruct()
            {
                ValueType     = 10,
                ReferenceType = "ABC",
            };
            var propertiesBag = new ExceptionPropertiesBag(exception);

            // Act
            CreateReflectionBasedDestructurer().Destructure(exception, propertiesBag, EmptyDestructurer());

            // Assert
            var properties          = propertiesBag.GetResultDictionary();
            var data                = (IDictionary)properties[nameof(Exception.Data)];
            var testStructDataValue = data["data"];

            Assert.IsAssignableFrom <TestStruct>(testStructDataValue);
        }
        public void CanDestructureFaultedTask()
        {
            var taskException = new Exception("INNER EXCEPTION MESSAGE");
            var task          = Task.FromException(taskException);
            var exception     = new TaskException("TASK EXCEPTION MESSAGE", task);

            var propertiesBag = new ExceptionPropertiesBag(exception);

            CreateReflectionBasedDestructurer().Destructure(exception, propertiesBag, InnerDestructurer(CreateReflectionBasedDestructurer()));

            var properties                 = propertiesBag.GetResultDictionary();
            var destructuredTaskObject     = (IDictionary)properties[nameof(TaskCanceledException.Task)];
            var destructuredTaskProperties = Assert.IsAssignableFrom <IDictionary <string, object> >(destructuredTaskObject);

            destructuredTaskProperties.Should().ContainKey(nameof(Task.Id));
            destructuredTaskProperties.Should().ContainKey(nameof(Task.Status))
            .WhichValue.Should().BeOfType <string>()
            .Which.Should().Be(nameof(TaskStatus.Faulted));
            destructuredTaskProperties.Should().ContainKey(nameof(Task.CreationOptions))
            .WhichValue.Should().BeOfType <string>()
            .Which.Should().Be(nameof(TaskCreationOptions.None));
            var taskFirstLevelExceptionDictionary = destructuredTaskProperties.Should().ContainKey(nameof(Task.Exception))
                                                    .WhichValue.Should().BeAssignableTo <IDictionary <string, object> >()
                                                    .Which;

            taskFirstLevelExceptionDictionary.Should().ContainKey("Message")
            .WhichValue.Should().BeOfType <string>()
            .Which.Should().Contain("One or more errors occurred.", "task's first level exception is aggregate exception");
            taskFirstLevelExceptionDictionary.Should().ContainKey("InnerExceptions")
            .WhichValue.Should().BeAssignableTo <IReadOnlyCollection <object> >()
            .Which.Should().ContainSingle()
            .Which.Should().BeAssignableTo <IDictionary <string, object> >()
            .Which.Should().ContainKey("Message")
            .WhichValue.Should().BeOfType <string>()
            .Which.Should().Be("INNER EXCEPTION MESSAGE");
        }
        public void WhenObjectContainsCyclicReferencesInDict_ThenRecursiveDestructureIsImmediatelyStopped()
        {
            // Arrange
            var cyclic = new MyObjectDict
            {
                Foo       = "Cyclic",
                Reference = new Dictionary <string, object>(),
            };

            cyclic.Reference["x"] = cyclic.Reference;
            var exception = new CyclicDictException
            {
                MyObjectDict = cyclic,
            };

            // Act
            var result       = new ExceptionPropertiesBag(new Exception());
            var destructurer = new ReflectionBasedDestructurer(10);

            destructurer.Destructure(exception, result, EmptyDestructurer());

            // Assert
            var myObject = (Dictionary <string, object>)result.GetResultDictionary()["MyObjectDict"];

            // exception.MyObjectDict["Reference"] is still regular dictionary
            var firstLevelDict = Assert.IsType <Dictionary <string, object> >(myObject["Reference"]);
            var id             = firstLevelDict["$id"];

            Assert.Equal("1", id);

            // exception.MyObjectDict["Reference"]["x"] we notice that we are destructuring same dictionary
            var secondLevelDict = Assert.IsType <Dictionary <string, object> >(firstLevelDict["x"]);
            var refId           = Assert.IsType <string>(secondLevelDict["$ref"]);

            Assert.Equal(id, refId);
        }
        public void CanDestructureClassDataItem()
        {
            // Arrange
            var exception = new Exception("test");

            exception.Data["data"] = new TestClass()
            {
                ValueType     = 10,
                ReferenceType = "ABC",
            };
            var propertiesBag = new ExceptionPropertiesBag(exception);

            // Act
            CreateReflectionBasedDestructurer().Destructure(exception, propertiesBag, EmptyDestructurer());

            // Assert
            var properties                   = propertiesBag.GetResultDictionary();
            var data                         = (IDictionary)properties[nameof(Exception.Data)];
            var testStructDataValue          = data["data"];
            var destructuredStructDictionary = Assert.IsAssignableFrom <IDictionary <string, object> >(testStructDataValue);

            Assert.Equal(10, destructuredStructDictionary[nameof(TestClass.ValueType)]);
            Assert.Equal("ABC", destructuredStructDictionary[nameof(TestClass.ReferenceType)]);
        }