Esempio n. 1
0
        /// <summary>
        /// Creates instance of <see cref="IValidator{T}"/> that can validate objects of type <typeparamref name="T"/> against the specification provided in the <paramref name="specificationHolder"/>.
        /// </summary>
        /// <param name="specificationHolder">Object that provides specification used to validate models (its member <see cref="ISpecificationHolder{T}.Specification"/>) and, optionally, settings (<see cref="ISettingsHolder.Settings"/>, if it implements also <see cref="ISettingsHolder"/>.</param>
        /// <param name="settings">Settings builder that helps adjust the created <see cref="IValidator{T}"/>'s settings. If not present, the default values are provided. Overrides translations delivered by <paramref name="specificationHolder"/>, if it implements also <see cref="ISettingsHolder"/>.</param>
        /// <typeparam name="T">Type of the models that this instance of <see cref="IValidator{T}"/> can validate.</typeparam>
        /// <returns>Instance of <see cref="IValidator{T}"/>, fully initialized and ready to work.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="specificationHolder"/> is null.</exception>
        /// <exception cref="InvalidOperationException">Thrown if <paramref name="specificationHolder"/>'s <see cref="ISettingsHolder.Settings"/> is null.</exception>
        public IValidator <T> Create <T>(ISpecificationHolder <T> specificationHolder, Func <ValidatorSettings, ValidatorSettings> settings = null)
        {
            if (specificationHolder is null)
            {
                throw new ArgumentNullException(nameof(specificationHolder));
            }

            var validatorSettings = ValidatorSettings.GetDefault();

            if (specificationHolder is ISettingsHolder validatorSettingsHolder)
            {
                if (validatorSettingsHolder.Settings is null)
                {
                    throw new ArgumentException($"{nameof(ISettingsHolder)} can't have null {nameof(ISettingsHolder.Settings)}", nameof(specificationHolder));
                }

                validatorSettings = GetResolvedSettings(validatorSettings, validatorSettingsHolder.Settings);
            }

            validatorSettings = GetResolvedSettings(validatorSettings, settings);

            var modelScheme = ModelSchemeFactory.Create(specificationHolder.Specification);

            SetReferenceLoopProtection(validatorSettings, modelScheme.IsReferenceLoopPossible);

            return(Create(specificationHolder.Specification, validatorSettings));
        }
Esempio n. 2
0
        public void Should_ThrowException_When_NullSpecification()
        {
            var capacityInfo = Substitute.For <ICapacityInfo>();

            Action action = () => ModelSchemeFactory.Create <TestClass>(null, capacityInfo);

            action.Should().ThrowExactly <ArgumentNullException>();
        }
Esempio n. 3
0
            public void Should_BeFalse_When_NoLoop_InDirectCase()
            {
                Specification <DirectLoopClassB> specificationB = c => c;

                Specification <DirectLoopClassA> specificationA = c => c.Member(m => m.B, m => m.AsModel(specificationB));

                var modelScheme = ModelSchemeFactory.Create(specificationA);

                modelScheme.IsReferenceLoopPossible.Should().BeFalse();
            }
Esempio n. 4
0
            public void Should_BeTrue_When_SelfLoop()
            {
                Specification <SelfLoop> specification = null;

                specification = c => c.Member(m => m.Self, m => m.AsModel(specification));

                var modelScheme = ModelSchemeFactory.Create(specification);

                modelScheme.IsReferenceLoopPossible.Should().BeTrue();
            }
Esempio n. 5
0
        /// <summary>
        /// Creates instance of <see cref="IValidator{T}"/> that can validate objects of type <typeparamref name="T"/> against the provided specification.
        /// </summary>
        /// <param name="specification">Specification used to validate models.</param>
        /// <param name="settings">Settings builder that helps adjust the created <see cref="IValidator{T}"/>'s settings. If not present, the default values are provided.</param>
        /// <typeparam name="T">Type of the models that this instance of <see cref="IValidator{T}"/> can validate.</typeparam>
        /// <returns>Instance of <see cref="IValidator{T}"/>, fully initialized and ready to work.</returns>
        public IValidator <T> Create <T>(Specification <T> specification, Func <ValidatorSettings, ValidatorSettings> settings = null)
        {
            var resolvedSettings = GetResolvedSettings(ValidatorSettings.GetDefault(), settings);

            var modelScheme = ModelSchemeFactory.Create(specification);

            SetReferenceLoopProtection(resolvedSettings, modelScheme.IsReferenceLoopPossible);

            return(Create(specification, resolvedSettings));
        }
Esempio n. 6
0
            public void Should_BeFalse_When_NoLoop_InSelfCase()
            {
                Specification <SelfLoop> specificationB = c => c;

                Specification <SelfLoop> specificationA = c => c.Member(m => m.Self, m => m.AsModel(specificationB));

                var modelScheme = ModelSchemeFactory.Create(specificationA);

                modelScheme.IsReferenceLoopPossible.Should().BeFalse();
            }
            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);
            }
Esempio n. 8
0
            public void Should_BeTrue_When_NestedLoop()
            {
                Specification <NestedLoopClassC> specificationC = null;

                Specification <NestedLoopClassB> specificationB = c => c.Member(m => m.C, m => m.AsModel(specificationC));

                Specification <NestedLoopClassA> specificationA = c => c.Member(m => m.B, m => m.AsModel(specificationB));

                specificationC = c => c.Member(m => m.A, m => m.AsModel(specificationA));

                var modelScheme = ModelSchemeFactory.Create(specificationA);

                modelScheme.IsReferenceLoopPossible.Should().BeTrue();
            }
            public void Should_GetLoopProtectionReferencesStackCount_BeNull_BeforeAndAfterEnteringRootScope_When_RootModelReference_IsNull(string id, Specification <TraversingTestCases.TestClassA> rootSpecification, TraversingTestCases.TestClassA model)
            {
                _ = id;

                var modelScheme = ModelSchemeFactory.Create(rootSpecification);

                var context = new IsValidValidationContext(modelScheme, default);

                context.GetLoopProtectionReferencesStackCount().Should().BeNull();

                context.EnterScope(modelScheme.RootSpecificationScopeId, model);

                context.GetLoopProtectionReferencesStackCount().Should().BeNull();
            }
Esempio n. 10
0
        public void Should_CreateModelScheme_With_Error()
        {
            Specification <TestClass> classSpecification = c => c.Rule(x => false).WithMessage("Invalid value custom message");

            var modelScheme = ModelSchemeFactory.Create(classSpecification);

            var error = modelScheme.ErrorRegistry.Where(e => e.Value.Args.Count == 0 && e.Value.Codes.Count == 0 && e.Value.Messages.Count == 1 && e.Value.Messages.Single() == "Invalid value custom message");

            error.Should().HaveCount(1);

            modelScheme.Template.Keys.Should().HaveCount(1);
            modelScheme.Template.Keys.Should().Contain("");
            modelScheme.Template[""].Should().Contain(error.Single().Key);
        }
Esempio n. 11
0
        public void Should_CreateModelScheme_And_InjectCapacityInfoHelpers_When_CapacityInfo_Is_CapacityInfoHelpersConsumer(bool feedable)
        {
            Specification <TestClass> classSpecification = c => c
                                                           .Optional()
                                                           .RuleTemplate(x => false, "Invalid value template message {argName}", Arg.Number("argName", 666L))
                                                           .Rule(x => false).WithMessage("Invalid value custom message")
                                                           .Rule(x => false).WithCode("CODE1");

            var capacityInfo = feedable
                ? Substitute.For <IFeedableCapacityInfo, ICapacityInfoHelpersConsumer>()
                : Substitute.For <ICapacityInfo, ICapacityInfoHelpersConsumer>();

            ModelSchemeFactory.Create(classSpecification, capacityInfo);

            (capacityInfo as ICapacityInfoHelpersConsumer).Received(1).InjectHelpers(NSubstitute.Arg.Is(ModelSchemeFactory.CapacityInfoHelpers));
        }
Esempio n. 12
0
        public void Should_CreateModelScheme_With_Errors()
        {
            Specification <TestClass> classSpecification = c => c
                                                           .RuleTemplate(x => false, "Invalid value template message {argName}", Arg.Number("argName", 666L))
                                                           .Rule(x => false).WithMessage("Invalid value custom message")
                                                           .Rule(x => false).WithCode("CODE1");

            var capacityInfo = Substitute.For <ICapacityInfo>();

            var modelScheme = ModelSchemeFactory.Create(classSpecification, capacityInfo);

            var error1Candidates = modelScheme.ErrorRegistry.Where(e => e.Value.Messages.Count == 1 && e.Value.Messages.Single() == "Invalid value custom message");

            error1Candidates.Should().HaveCount(1);
            var error1 = error1Candidates.Single();

            error1.Value.Codes.Should().BeEmpty();
            error1.Value.Args.Should().BeEmpty();

            var error2Candidates = modelScheme.ErrorRegistry.Where(e => e.Value.Messages.Count == 1 && e.Value.Messages.Single() == "Invalid value template message {argName}");

            error2Candidates.Should().HaveCount(1);
            var error2 = error2Candidates.Single();

            error2.Value.Codes.Should().BeEmpty();
            error2.Value.Args.Should().HaveCount(1);
            var error2Arg = error2.Value.Args.Single();

            error2Arg.Should().BeOfType <NumberArg <long> >();
            ((NumberArg <long>)error2Arg).Name.Should().Be("argName");
            ((NumberArg <long>)error2Arg).Value.Should().Be(666);

            var error3Candidates = modelScheme.ErrorRegistry.Where(e => e.Value.Codes.Count == 1 && e.Value.Codes.Single() == "CODE1");

            error3Candidates.Should().HaveCount(1);
            var error3 = error3Candidates.Single();

            error3.Value.Messages.Should().BeEmpty();
            error3.Value.Args.Should().BeEmpty();

            modelScheme.Template.Keys.Should().HaveCount(1);
            modelScheme.Template.Keys.Should().Contain("");
            modelScheme.Template[""].Should().Contain(error1.Key);
            modelScheme.Template[""].Should().Contain(error2.Key);
            modelScheme.Template[""].Should().Contain(error3.Key);
        }
Esempio n. 13
0
        /// <summary>
        /// Creates instance of <see cref="IValidator{T}"/> that can validate objects of type <typeparamref name="T"/> against the provided specification.
        /// </summary>
        /// <param name="specification">Specification used to validate models.</param>
        /// <param name="settings">Settings used to validate models.</param>
        /// <typeparam name="T">Type of the models that this instance of <see cref="IValidator{T}"/> can validate.</typeparam>
        /// <returns>Instance of <see cref="IValidator{T}"/>, fully initialized and ready to work.</returns>
        /// <exception cref="ArgumentNullException">Thrown if <paramref name="settings"/> is null.</exception>
        /// <exception cref="ArgumentException">Thrown if <paramref name="settings"/> is not an instance of <see cref="ValidatorSettings"/>.</exception>
        public IValidator <T> Create <T>(Specification <T> specification, IValidatorSettings settings)
        {
            var modelScheme = ModelSchemeFactory.Create(specification);

            if (settings is null)
            {
                throw new ArgumentNullException(nameof(settings));
            }

            if (!(settings is ValidatorSettings validatorSettings))
            {
                throw new ArgumentException($"Custom {nameof(IValidatorSettings)} implementations are not supported.", nameof(settings));
            }

            validatorSettings.IsLocked = true;

            return(new Validator <T>(modelScheme, settings));
        }
            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)");
            }
Esempio n. 15
0
        public void Should_CreateModelScheme_And_FeedCapacityInfo_When_ShouldFeed_IsTrue()
        {
            Specification <TestClass> classSpecification = c => c
                                                           .Optional()
                                                           .RuleTemplate(x => false, "Invalid value template message {argName}", Arg.Number("argName", 666L))
                                                           .Rule(x => false).WithMessage("Invalid value custom message")
                                                           .Rule(x => false).WithCode("CODE1");

            var feedableCapacityInfo = Substitute.For <IFeedableCapacityInfo>();

            IErrorsHolder errorsHolders = null;

            feedableCapacityInfo.ShouldFeed.Returns(true);

            feedableCapacityInfo.When(x => x.Feed(NSubstitute.Arg.Any <IErrorsHolder>())).Do(callInfo =>
            {
                errorsHolders = callInfo.Arg <IErrorsHolder>();
            });

            ModelSchemeFactory.Create(classSpecification, feedableCapacityInfo);

            feedableCapacityInfo.ReceivedWithAnyArgs(1).Feed(default);
Esempio n. 16
0
        public void Should_CreateModelScheme_With_PathResolved()
        {
            Specification <TestMember> memberSpecification = c => c.Rule(x => false).WithMessage("Member error");

            Specification <TestClass> classSpecification = c => c
                                                           .Member(m => m.Member, memberSpecification).WithPath("TestNested")
                                                           .Rule(x => false).WithPath("TestNested").WithMessage("Base error");

            var modelScheme = ModelSchemeFactory.Create(classSpecification);

            var memberError = modelScheme.ErrorRegistry.Single(e => e.Value.Messages.Count == 1 && e.Value.Messages.Single() == "Member error");

            var baseError = modelScheme.ErrorRegistry.Single(e => e.Value.Messages.Count == 1 && e.Value.Messages.Single() == "Base error");

            modelScheme.Template.Keys.Should().HaveCount(2);
            modelScheme.Template.Keys.Should().Contain("");
            modelScheme.Template[""].Should().NotContain(memberError.Key);
            modelScheme.Template[""].Should().NotContain(baseError.Key);
            modelScheme.Template.Keys.Should().Contain("TestNested");
            modelScheme.Template["TestNested"].Should().Contain(memberError.Key);
            modelScheme.Template["TestNested"].Should().Contain(baseError.Key);
        }
Esempio n. 17
0
        public void Should_ThrowException_When_NullCapacityInfo()
        {
            Action action = () => ModelSchemeFactory.Create <TestClass>(m => m, null);

            action.Should().ThrowExactly <ArgumentNullException>();
        }
Esempio n. 18
0
        public void Should_ThrowException_When_NullSpecification()
        {
            Action action = () => ModelSchemeFactory.Create <TestClass>(null);

            action.Should().ThrowExactly <ArgumentNullException>();
        }
Esempio n. 19
0
 public void Should_CreateModelScheme()
 {
     _ = ModelSchemeFactory.Create <TestClass>(m => m);
 }
Esempio n. 20
0
        public void Should_CreateModelScheme()
        {
            var capacityInfo = Substitute.For <ICapacityInfo>();

            _ = ModelSchemeFactory.Create <TestClass>(m => m, capacityInfo);
        }
Esempio n. 21
0
        public void Should_CreateModelScheme_With_Errors_And_NestedSpecifications()
        {
            Specification <TestMember> memberSpecification = c => c.Optional().RuleTemplate(x => false, "Nested template message", Arg.Number("nestedArg", 100M)).WithExtraCode("CODE_N");

            Specification <TestClass> classSpecification = c => c
                                                           .Optional()
                                                           .Member(m => m.Member, memberSpecification)
                                                           .RuleTemplate(x => false, "Invalid value template message {argName}", Arg.Number("argName", 666L))
                                                           .Rule(x => false).WithMessage("Invalid value custom message")
                                                           .Rule(x => false).WithCode("CODE1");

            var modelScheme = ModelSchemeFactory.Create(classSpecification);

            var error1Candidates = modelScheme.ErrorRegistry.Where(e => e.Value.Messages.Count == 1 && e.Value.Messages.Single() == "Invalid value template message {argName}");

            error1Candidates.Should().HaveCount(1);
            var error1 = error1Candidates.Single();

            error1.Value.Codes.Should().BeEmpty();
            error1.Value.Args.Should().HaveCount(1);
            var error1Arg = error1.Value.Args.Single();

            error1Arg.Should().BeOfType <NumberArg <long> >();
            ((NumberArg <long>)error1Arg).Name.Should().Be("argName");
            ((NumberArg <long>)error1Arg).Value.Should().Be(666);

            var error2Candidates = modelScheme.ErrorRegistry.Where(e => e.Value.Messages.Count == 1 && e.Value.Messages.Single() == "Invalid value custom message");

            error2Candidates.Should().HaveCount(1);
            var error2 = error2Candidates.Single();

            error2.Value.Codes.Should().BeEmpty();
            error2.Value.Args.Should().BeEmpty();

            var error3Candidates = modelScheme.ErrorRegistry.Where(e => e.Value.Codes.Count == 1 && e.Value.Codes.Single() == "CODE1");

            error3Candidates.Should().HaveCount(1);
            var error3 = error3Candidates.Single();

            error3.Value.Messages.Should().BeEmpty();
            error3.Value.Args.Should().BeEmpty();

            var errorNestedCandidates = modelScheme.ErrorRegistry.Where(e => e.Value.Messages.Count == 1 && e.Value.Messages.Single() == "Nested template message");

            errorNestedCandidates.Should().HaveCount(1);
            var errorNested = errorNestedCandidates.Single();

            errorNested.Value.Codes.Should().HaveCount(1);
            errorNested.Value.Codes.Single().Should().Be("CODE_N");
            errorNested.Value.Args.Should().HaveCount(1);
            var errorNestedArg = errorNested.Value.Args.Single();

            errorNestedArg.Should().BeOfType <NumberArg <decimal> >();
            (errorNestedArg as NumberArg <decimal>).Name.Should().Be("nestedArg");
            (errorNestedArg as NumberArg <decimal>).Value.Should().Be(100);

            modelScheme.Template.Keys.Should().HaveCount(2);
            modelScheme.Template.Keys.Should().Contain("");
            modelScheme.Template[""].Should().Contain(error2.Key);
            modelScheme.Template[""].Should().Contain(error2.Key);
            modelScheme.Template[""].Should().Contain(error3.Key);
            modelScheme.Template.Keys.Should().Contain("Member");
            modelScheme.Template["Member"].Should().Contain(errorNested.Key);
        }