Esempio n. 1
0
        public void CanAddValidationComponentsTest()
        {
            var vc = new ValidationContext(ImmediateScheduler.Instance);

            var invalidName = string.Empty;

            var vm = new TestViewModel {
                Name = "valid"
            };

            var v1 = new BasePropertyValidation <TestViewModel, string>(
                vm,
                v => v.Name,
                s => !string.IsNullOrEmpty(s),
                msg => $"{msg} isn't valid");

            vc.Add(v1);

            Assert.True(vc.IsValid);

            vm.Name = invalidName;

            Assert.False(v1.IsValid);
            Assert.False(vc.IsValid);

            Assert.Equal(1, vc.Text.Count);
        }
Esempio n. 2
0
        public void RegisterValidationsWithDifferentLambdaNameWorksTest()
        {
            const string validName     = "valid";
            const int    minimumLength = 5;

            var viewModel = new TestViewModel {
                Name = validName
            };
            var view = new TestView(viewModel);

            var firstValidation = new BasePropertyValidation <TestViewModel, string>(
                viewModel,
                viewModelProperty => viewModelProperty.Name,
                s => !string.IsNullOrEmpty(s),
                s => $"Name {s} isn't valid");

            // Add validations
            viewModel.ValidationContext.Add(firstValidation);

            // View bindings
            view.Bind(view.ViewModel, vm => vm.Name, v => v.NameLabel);

            // This was throwing exception due to naming problems with lambdas expressions
            view.BindValidation(
                view.ViewModel,
                vm => vm.Name,
                v => v.NameErrorLabel);

            Assert.True(viewModel.ValidationContext.IsValid);
            Assert.Equal(1, viewModel.ValidationContext.Validations.Count);
        }
        public void ValidationMessagesDefaultConcatenationTest()
        {
            var viewModel = new TestViewModel {
                Name = string.Empty
            };
            var view = new TestView(viewModel);

            var nameValidation = new BasePropertyValidation <TestViewModel, string>(
                viewModel,
                viewModelProperty => viewModelProperty.Name,
                s => !string.IsNullOrEmpty(s),
                "Name should not be empty.");

            var name2Validation = new BasePropertyValidation <TestViewModel, string>(
                viewModel,
                viewModelProperty => viewModelProperty.Name2,
                s => !string.IsNullOrEmpty(s),
                "Name2 should not be empty.");

            viewModel.ValidationContext.Add(nameValidation);
            viewModel.ValidationContext.Add(name2Validation);

            view.Bind(view.ViewModel, vm => vm.Name, v => v.NameLabel);
            view.Bind(view.ViewModel, vm => vm.Name2, v => v.Name2Label);
            view.BindValidation(view.ViewModel, v => v.NameErrorLabel);

            Assert.False(viewModel.ValidationContext.IsValid);
            Assert.Equal(2, viewModel.ValidationContext.Validations.Count);
            Assert.NotEmpty(view.NameErrorLabel);
            Assert.Equal("Name should not be empty. Name2 should not be empty.", view.NameErrorLabel);
        }
Esempio n. 4
0
        public void MessageUpdatedWhenPropertyChanged()
        {
            const string testRoot  = "bon";
            const string testValue = testRoot + "go";

            var model = new TestViewModel();

            var validation = new BasePropertyValidation <TestViewModel, string>(
                model,
                vm => vm.Name,
                n => n != null && n.Length > testValue.Length,
                v => $"The value '{v}' is incorrect");

            model.Name = testValue;

            var changes = new List <ValidationState>();

            validation.ValidationStatusChange.Subscribe(v => changes.Add(v));

            Assert.Equal("The value 'bongo' is incorrect", validation.Text.ToSingleLine());
            Assert.Single(changes);
            Assert.Equal(new ValidationState(false, "The value 'bongo' is incorrect", validation), changes[0], new ValidationStateComparer());

            model.Name = testRoot;

            Assert.Equal("The value 'bon' is incorrect", validation.Text.ToSingleLine());
            Assert.Equal(2, changes.Count);
            Assert.Equal(new ValidationState(false, "The value 'bon' is incorrect", validation), changes[1], new ValidationStateComparer());
        }
Esempio n. 5
0
        public void StateTransitionsWhenValidityChangesTest()
        {
            const string testValue = "test";

            var model = new TestViewModel();

            var validation = new BasePropertyValidation <TestViewModel, string>(
                model,
                vm => vm.Name,
                n => n != null && n.Length >= testValue.Length,
                "broken");

            bool?lastVal = null;

            var unused = validation
                         .ValidationStatusChange
                         .Subscribe(v => lastVal = v.IsValid);

            Assert.False(validation.IsValid);
            Assert.False(lastVal);
            Assert.True(lastVal.HasValue);

            model.Name = testValue + "-" + testValue;

            Assert.True(validation.IsValid);
            Assert.True(lastVal);
        }
Esempio n. 6
0
    public void ShouldFireErrorsChangedEventWhenValidationStateChanges()
    {
        var viewModel = new IndeiTestViewModel();

        DataErrorsChangedEventArgs arguments = null;

        viewModel.ErrorsChanged += (_, args) => arguments = args;

        using var firstValidation = new BasePropertyValidation <IndeiTestViewModel, string>(
                  viewModel,
                  vm => vm.Name,
                  s => !string.IsNullOrEmpty(s),
                  NameShouldNotBeEmptyMessage);

        viewModel.ValidationContext.Add(firstValidation);

        Assert.True(viewModel.HasErrors);
        Assert.False(viewModel.ValidationContext.IsValid);
        Assert.Single(viewModel.ValidationContext.Validations);
        Assert.Single(viewModel.GetErrors("Name").Cast <string>());

        viewModel.Name = "JoJo";

        Assert.False(viewModel.HasErrors);
        Assert.Empty(viewModel.GetErrors("Name").Cast <string>());
        Assert.NotNull(arguments);
        Assert.Equal("Name", arguments.PropertyName);
    }
        public void ShouldSupportBindingToValidationContextWrappedInValidationHelper()
        {
            const string nameValidationError = "Name should not be empty.";
            var          view = new TestView(new TestViewModel {
                Name = string.Empty
            });
            var outerContext = new ValidationContext(ImmediateScheduler.Instance);
            var validation   = new BasePropertyValidation <TestViewModel, string>(
                view.ViewModel,
                vm => vm.Name,
                name => !string.IsNullOrWhiteSpace(name),
                nameValidationError);

            outerContext.Add(validation);
            view.ViewModel.NameRule = new ValidationHelper(outerContext);

            view.Bind(view.ViewModel, vm => vm.Name, v => v.NameLabel);
            view.BindValidation(view.ViewModel, vm => vm.NameRule, v => v.NameErrorLabel);

            Assert.False(view.ViewModel.NameRule.IsValid);
            Assert.NotEmpty(view.NameErrorLabel);
            Assert.Equal(nameValidationError, view.NameErrorLabel);

            view.ViewModel.Name = "Jotaro";

            Assert.True(view.ViewModel.NameRule.IsValid);
            Assert.Empty(view.NameErrorLabel);
        }
        public void ValidModelDefaultState()
        {
            var model = CreateDefaultValidModel();

            var validation = new BasePropertyValidation <TestViewModel, string>(model,
                                                                                vm => vm.Name,
                                                                                (n) => !string.IsNullOrEmpty(n), "broken");

            Assert.True(validation.IsValid);
            Assert.True(string.IsNullOrEmpty(validation.Text.ToSingleLine()));
        }
Esempio n. 9
0
        public void PropertyContentsProvidedToMessageTest()
        {
            const string testValue = "bongo";

            var model = new TestViewModel();

            var validation = new BasePropertyValidation <TestViewModel, string>(
                model,
                vm => vm.Name,
                n => n != null && n.Length > testValue.Length,
                v => $"The value '{v}' is incorrect");

            model.Name = testValue;

            Assert.Equal("The value 'bongo' is incorrect", validation.Text.ToSingleLine());
        }
Esempio n. 10
0
        public void TwoValidationPropertiesInSamePropertyThrowsExceptionTest()
        {
            const string validName     = "valid";
            const int    minimumLength = 5;

            var viewModel = new TestViewModel {
                Name = validName
            };
            var view = new TestView(viewModel);

            var firstValidation = new BasePropertyValidation <TestViewModel, string>(
                viewModel,
                vm => vm.Name,
                s => !string.IsNullOrEmpty(s),
                s => $"Name {s} isn't valid");

            var secondValidation = new BasePropertyValidation <TestViewModel, string>(
                viewModel,
                vm => vm.Name,
                s => s.Length > minimumLength,
                _ => $"Minimum length is {minimumLength}");

            // Add validations
            viewModel.ValidationContext.Add(firstValidation);
            viewModel.ValidationContext.Add(secondValidation);

            // View bindings
            view.Bind(view.ViewModel, vm => vm.Name, v => v.NameLabel);

            // View validations bindings
            var ex = Assert.Throws <MultipleValidationNotSupportedException>(() =>
            {
                return(view.BindValidation(
                           view.ViewModel,
                           vm => vm.Name,
                           v => v.NameErrorLabel));
            });

            Assert.False(viewModel.ValidationContext.IsValid);
            Assert.Equal(2, viewModel.ValidationContext.Validations.Count);

            // Checks if second validation error message is shown
            var expectedError =
                $"Property {nameof(viewModel.Name)} has more than one validation rule associated. Consider using {nameof(ValidationBindingEx)} methods.";

            Assert.Equal(expectedError, ex.Message);
        }
Esempio n. 11
0
        public void TwoValidationComponentsCorrectlyResultInContextTest()
        {
            const string validName   = "valid";
            var          invalidName = string.Empty;

            var vc = new ValidationContext(ImmediateScheduler.Instance);

            var vm = new TestViewModel {
                Name = validName, Name2 = validName
            };

            var firstValidation = new BasePropertyValidation <TestViewModel, string>(
                vm,
                v => v.Name,
                s => !string.IsNullOrEmpty(s),
                s => $"Name {s} isn't valid");

            var secondValidation = new BasePropertyValidation <TestViewModel, string>(
                vm,
                v => v.Name2,
                s => !string.IsNullOrEmpty(s),
                s => $"Name 2 {s} isn't valid");

            vc.Add(firstValidation);
            vc.Add(secondValidation);

            Assert.True(vc.IsValid);
            Assert.Equal(0, vc.Text.Count);

            vm.Name = invalidName;
            Assert.False(vc.IsValid);
            Assert.Equal(1, vc.Text.Count);
            Assert.Equal("Name " + invalidName + " isn't valid", vc.Text[0]);

            vm.Name2 = invalidName;
            Assert.False(vc.IsValid);
            Assert.Equal(2, vc.Text.Count);
            Assert.Equal("Name " + invalidName + " isn't valid", vc.Text[0]);
            Assert.Equal("Name 2 " + invalidName + " isn't valid", vc.Text[1]);

            vm.Name  = validName;
            vm.Name2 = validName;

            Assert.True(vc.IsValid);
            Assert.Equal(0, vc.Text.Count);
        }
        /// <summary>
        /// Setup a validation rule for a specified ViewModel property with dynamic error message.
        /// </summary>
        /// <typeparam name="TViewModel">ViewModel type.</typeparam>
        /// <typeparam name="TViewModelProp">ViewModel property type.</typeparam>
        /// <param name="viewModel">ViewModel instance.</param>
        /// <param name="viewModelProperty">ViewModel property.</param>
        /// <param name="isPropertyValid">Func to define if the viewModelProperty is valid or not.</param>
        /// <param name="message">Func to define the validation error message based on the viewModelProperty value.</param>
        /// <returns>Returns a <see cref="ValidationHelper"/> object.</returns>
        public static ValidationHelper ValidationRule <TViewModel, TViewModelProp>(
            this TViewModel viewModel,
            Expression <Func <TViewModel, TViewModelProp> > viewModelProperty,
            Func <TViewModelProp, bool> isPropertyValid,
            Func <TViewModelProp, string> message)
            where TViewModel : ReactiveObject, ISupportsValidation
        {
            // We need to associate the ViewModel property
            // with something that can be easily looked up and bound to
            var propValidation = new BasePropertyValidation <TViewModel, TViewModelProp>(
                viewModel,
                viewModelProperty,
                isPropertyValid,
                message);

            viewModel.ValidationContext.Add(propValidation);

            return(new ValidationHelper(propValidation));
        }
    public void ShouldClearAttachedValidationRulesForTheGivenProperty()
    {
        var viewModel = new TestViewModel {
            Name = string.Empty
        };

        using var nameValidation = new BasePropertyValidation <TestViewModel, string>(
                  viewModel,
                  viewModelProperty => viewModelProperty.Name,
                  s => !string.IsNullOrEmpty(s),
                  "Name should not be empty.");

        const string name2ErrorMessage = "Name2 should not be empty.";

        using var name2Validation = new BasePropertyValidation <TestViewModel, string>(
                  viewModel,
                  viewModelProperty => viewModelProperty.Name2,
                  s => !string.IsNullOrEmpty(s),
                  name2ErrorMessage);

        viewModel.ValidationContext.Add(nameValidation);
        viewModel.ValidationContext.Add(name2Validation);

        Assert.Equal(2, viewModel.ValidationContext.Validations.Count);
        Assert.False(viewModel.ValidationContext.IsValid);
        Assert.NotEmpty(viewModel.ValidationContext.Text);
        Assert.Throws <ArgumentNullException>(() => viewModel.ClearValidationRules <TestViewModel, string>(null !));

        viewModel.ClearValidationRules(x => x.Name);

        Assert.Equal(1, viewModel.ValidationContext.Validations.Count);
        Assert.False(viewModel.ValidationContext.IsValid);
        Assert.NotEmpty(viewModel.ValidationContext.Text);
        Assert.Equal(name2ErrorMessage, viewModel.ValidationContext.Text.ToSingleLine());

        // Verify that the method is idempotent.
        viewModel.ClearValidationRules(x => x.Name);

        Assert.Equal(1, viewModel.ValidationContext.Validations.Count);
        Assert.False(viewModel.ValidationContext.IsValid);
        Assert.NotEmpty(viewModel.ValidationContext.Text);
        Assert.Equal(name2ErrorMessage, viewModel.ValidationContext.Text.ToSingleLine());
    }
Esempio n. 14
0
    public void ShouldSynchronizeNotifyDataErrorInfoWithValidationContext()
    {
        var viewModel = new IndeiTestViewModel();
        var view      = new IndeiTestView(viewModel);

        using var firstValidation = new BasePropertyValidation <IndeiTestViewModel, string>(
                  viewModel,
                  vm => vm.Name,
                  s => !string.IsNullOrEmpty(s),
                  NameShouldNotBeEmptyMessage);

        viewModel.ValidationContext.Add(firstValidation);
        view.Bind(view.ViewModel, vm => vm.Name, v => v.NameLabel);
        view.BindValidation(view.ViewModel, vm => vm.Name, v => v.NameErrorLabel);

        // Verify the initial state.
        Assert.True(viewModel.HasErrors);
        Assert.False(viewModel.ValidationContext.IsValid);
        Assert.Single(viewModel.ValidationContext.Validations);
        Assert.Equal(NameShouldNotBeEmptyMessage, viewModel.GetErrors("Name").Cast <string>().First());
        Assert.Equal(NameShouldNotBeEmptyMessage, view.NameErrorLabel);

        // Send INotifyPropertyChanged.
        viewModel.Name = "JoJo";

        // Verify the changed state.
        Assert.False(viewModel.HasErrors);
        Assert.True(viewModel.ValidationContext.IsValid);
        Assert.Empty(viewModel.GetErrors("Name").Cast <string>());
        Assert.Empty(view.NameErrorLabel);

        // Send INotifyPropertyChanged.
        viewModel.Name = string.Empty;

        // Verify the changed state.
        Assert.True(viewModel.HasErrors);
        Assert.False(viewModel.ValidationContext.IsValid);
        Assert.Single(viewModel.ValidationContext.Validations);
        Assert.Equal(NameShouldNotBeEmptyMessage, viewModel.GetErrors("Name").Cast <string>().First());
        Assert.Equal(NameShouldNotBeEmptyMessage, view.NameErrorLabel);
    }
Esempio n. 15
0
        public void DualStateMessageTest()
        {
            const string testRoot  = "bon";
            const string testValue = testRoot + "go";

            var model = new TestViewModel {
                Name = testValue
            };

            var validation = new BasePropertyValidation <TestViewModel, string>(
                model,
                vm => vm.Name,
                n => n != null && n.Length > testRoot.Length,
                (p, v) => v ? "cool" : $"The value '{p}' is incorrect");

            Assert.Equal("cool", validation.Text.ToSingleLine());

            model.Name = testRoot;

            Assert.Equal("The value 'bon' is incorrect", validation.Text.ToSingleLine());
        }
        public void ShouldSupportBindingTwoValidationsForOneProperty()
        {
            const int minimumLength = 5;

            var viewModel = new TestViewModel {
                Name = "some"
            };
            var view = new TestView(viewModel);

            var firstValidation = new BasePropertyValidation <TestViewModel, string>(
                viewModel,
                vm => vm.Name,
                s => !string.IsNullOrEmpty(s),
                "Name is required.");

            var minimumLengthErrorMessage = $"Minimum length is {minimumLength}";
            var secondValidation          = new BasePropertyValidation <TestViewModel, string>(
                viewModel,
                vm => vm.Name,
                s => s.Length > minimumLength,
                s => minimumLengthErrorMessage);

            // Add validations
            viewModel.ValidationContext.Add(firstValidation);
            viewModel.ValidationContext.Add(secondValidation);

            // View bindings
            view.Bind(view.ViewModel, vm => vm.Name, v => v.NameLabel);

            // View validations bindings
            view.BindValidation(view.ViewModel, vm => vm.Name, v => v.NameErrorLabel);

            viewModel.Name = "som";

            Assert.False(viewModel.ValidationContext.IsValid);
            Assert.Equal(2, viewModel.ValidationContext.Validations.Count);

            // Checks if second validation error message is shown
            Assert.Equal(minimumLengthErrorMessage, view.NameErrorLabel);
        }
        /// <summary>
        /// Setup a validation rule for a specified ViewModel property with dynamic error message.
        /// </summary>
        /// <typeparam name="TViewModel">ViewModel type.</typeparam>
        /// <typeparam name="TViewModelProp">ViewModel property type.</typeparam>
        /// <param name="viewModel">ViewModel instance.</param>
        /// <param name="viewModelProperty">ViewModel property.</param>
        /// <param name="isPropertyValid">Func to define if the viewModelProperty is valid or not.</param>
        /// <param name="message">Func to define the validation error message based on the viewModelProperty value.</param>
        /// <returns>Returns a <see cref="ValidationHelper"/> object.</returns>
        public static ValidationHelper ValidationRule <TViewModel, TViewModelProp>(
            this TViewModel viewModel,
            Expression <Func <TViewModel, TViewModelProp> > viewModelProperty,
            Func <TViewModelProp, bool> isPropertyValid,
            Func <TViewModelProp, string> message)
            where TViewModel : ReactiveObject, IValidatableViewModel
        {
            if (viewModel is null)
            {
                throw new ArgumentNullException(nameof(viewModel));
            }

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

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

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

            // We need to associate the ViewModel property
            // with something that can be easily looked up and bound to
            var propValidation = new BasePropertyValidation <TViewModel, TViewModelProp>(
                viewModel,
                viewModelProperty,
                isPropertyValid,
                message);

            viewModel.ValidationContext.Add(propValidation);

            return(new ValidationHelper(propValidation));
        }
    public void ShouldClearAttachedValidationRules()
    {
        var viewModel = new TestViewModel {
            Name = string.Empty
        };

        using var nameValidation = new BasePropertyValidation <TestViewModel, string>(
                  viewModel,
                  viewModelProperty => viewModelProperty.Name,
                  s => !string.IsNullOrEmpty(s),
                  "Name should not be empty.");

        using var name2Validation = new BasePropertyValidation <TestViewModel, string>(
                  viewModel,
                  viewModelProperty => viewModelProperty.Name2,
                  s => !string.IsNullOrEmpty(s),
                  "Name2 should not be empty.");

        viewModel.ValidationContext.Add(nameValidation);
        viewModel.ValidationContext.Add(name2Validation);

        Assert.Equal(2, viewModel.ValidationContext.Validations.Count);
        Assert.False(viewModel.ValidationContext.IsValid);
        Assert.NotEmpty(viewModel.ValidationContext.Text);

        viewModel.ClearValidationRules();

        Assert.Equal(0, viewModel.ValidationContext.Validations.Count);
        Assert.True(viewModel.ValidationContext.IsValid);
        Assert.Empty(viewModel.ValidationContext.Text);

        // Verify that the method is idempotent.
        viewModel.ClearValidationRules();

        Assert.Equal(0, viewModel.ValidationContext.Validations.Count);
        Assert.True(viewModel.ValidationContext.IsValid);
        Assert.Empty(viewModel.ValidationContext.Text);
    }
Esempio n. 19
0
    public void ShouldMarkPropertiesAsInvalidOnInit()
    {
        var viewModel = new IndeiTestViewModel();
        var view      = new IndeiTestView(viewModel);

        using var firstValidation = new BasePropertyValidation <IndeiTestViewModel, string>(
                  viewModel,
                  vm => vm.Name,
                  s => !string.IsNullOrEmpty(s),
                  NameShouldNotBeEmptyMessage);

        viewModel.ValidationContext.Add(firstValidation);
        view.Bind(view.ViewModel, vm => vm.Name, v => v.NameLabel);
        view.BindValidation(view.ViewModel, vm => vm.Name, v => v.NameErrorLabel);

        // Verify validation context behavior.
        Assert.False(viewModel.ValidationContext.IsValid);
        Assert.Single(viewModel.ValidationContext.Validations);
        Assert.Equal(NameShouldNotBeEmptyMessage, view.NameErrorLabel);

        // Verify INotifyDataErrorInfo behavior.
        Assert.True(viewModel.HasErrors);
        Assert.Equal(NameShouldNotBeEmptyMessage, viewModel.GetErrors("Name").Cast <string>().First());
    }
    public void IsValidShouldNotifyOfValidityChange()
    {
        var viewModel = new TestViewModel {
            Name = string.Empty
        };

        using var nameValidation = new BasePropertyValidation <TestViewModel, string>(
                  viewModel,
                  viewModelProperty => viewModelProperty.Name,
                  s => !string.IsNullOrEmpty(s),
                  "Name should not be empty.");
        viewModel.ValidationContext.Add(nameValidation);

        var latestValidity = false;

        viewModel.IsValid().Subscribe(isValid => latestValidity = isValid);
        Assert.False(latestValidity);

        viewModel.Name = "Jonathan";
        Assert.True(latestValidity);

        viewModel.Name = string.Empty;
        Assert.False(latestValidity);
    }