public void Should_Initialize_ReferencesStack_With_One_When_LoopProtectionSettings_Has_RootModel_And_RootModelTypeInSchemeIsReferenceType()
            {
                var modelScheme = Substitute.For <IModelScheme>();

                modelScheme.RootModelType.Returns(typeof(object));

                var validationContext = new IsValidValidationContext(
                    modelScheme,
                    new ReferenceLoopProtectionSettings(new object()));

                validationContext.GetLoopProtectionReferencesStackCount().Should().Be(1);
            }
            public void Should_Initialize_ReferencesStack_With_Zero_When_LoopProtectionSettings_Has_NullRootModel(bool rootModelTypeIsReference)
            {
                var modelScheme = Substitute.For <IModelScheme>();

                modelScheme.RootModelType.Returns(rootModelTypeIsReference ? typeof(object) : typeof(int));

                var validationContext = new IsValidValidationContext(
                    modelScheme,
                    new ReferenceLoopProtectionSettings());

                validationContext.GetLoopProtectionReferencesStackCount().Should().Be(0);
            }
            public void Should_Initialize_WithReferenceLoopProtectionSettings()
            {
                var modelScheme = Substitute.For <IModelScheme>();

                modelScheme.RootModelType.Returns(typeof(object));

                var referenceLoopProtectionSettings = new ReferenceLoopProtectionSettings();

                var validationContext = new IsValidValidationContext(modelScheme, referenceLoopProtectionSettings);

                validationContext.ReferenceLoopProtectionSettings.Should().BeSameAs(referenceLoopProtectionSettings);
            }
            public void Should_GetLoopProtectionReferencesStackCount_BeOne_BeforeAndAfterEnteringRootScope_When_RootModelReference_Exists(string id, Specification <TraversingTestCases.TestClassA> rootSpecification, TraversingTestCases.TestClassA model)
            {
                _ = id;

                var modelScheme = ModelSchemeFactory.Create(rootSpecification);

                var context = new IsValidValidationContext(modelScheme, new ReferenceLoopProtectionSettings(new object()));

                context.GetLoopProtectionReferencesStackCount().Should().Be(1);

                context.EnterScope(modelScheme.RootSpecificationScopeId, model);

                context.GetLoopProtectionReferencesStackCount().Should().Be(1);
            }
            public void Should_ThrowException_InfiniteReferencesLoopException_WithDetectedLoopInfo_When_ReferencesLoopDetected(string testId, Specification <TraversingTestCases.LoopClassA> specification, TraversingTestCases.LoopClassA model, string path, string infiniteLoopNestedPath, Type type)
            {
                _ = testId;
                _ = path;
                _ = infiniteLoopNestedPath;

                var modelScheme = ModelSchemeFactory.Create(specification);

                var context = new IsValidValidationContext(modelScheme, new ReferenceLoopProtectionSettings());

                Action action = () => context.EnterScope(modelScheme.RootSpecificationScopeId, model);

                var exception = action.Should().ThrowExactly <ReferenceLoopException>().And;

                exception.Path.Should().BeNull();
                exception.NestedPath.Should().BeNull();
                exception.Type.Should().Be(type);

                exception.Message.Should().Be($"Reference loop detected: object of type {type.GetFriendlyName()} has been detected twice in the reference graph, effectively creating the infinite references loop (where exactly, that information is not available - is that validation comes from IsValid method, please repeat it using the Validate method and examine the exception thrown)");
            }