Inheritance: System.ComponentModel.DataAnnotations.ValidationAttribute
        public void return_null_in_place_of_member_name_when_it_cannot_be_unambiguously_retrieved()
        {
            var model = new DisplayDuplicateModel();
            var attrib = new AssertThatAttribute("false");

            Assert.Equal(null, GetFinalMemberName(attrib, model, 0, null, "duplicate"));
        }
        public void throw_when_no_httpcontext_is_available()
        {
            HttpContext.Current = null;

            var model = new Model();
            var assertAttribute = new AssertThatAttribute("true");
            var requirAttribute = new RequiredIfAttribute("true");

            var metadata = GetModelMetadata(model, m => m.Value);
            var controllerContext = GetControllerContext();

            var e = Assert.Throws<ValidationException>(() => new AssertThatValidator(metadata, controllerContext, assertAttribute).GetClientValidationRules().Single());
            Assert.Equal(
                "AssertThatValidator: collecting of client validation rules for Value field failed.",
                e.Message);
            Assert.IsType<ApplicationException>(e.InnerException);
            Assert.Equal(
                "HttpContext not available.",
                e.InnerException.Message);

            e = Assert.Throws<ValidationException>(() => new RequiredIfValidator(metadata, controllerContext, requirAttribute).GetClientValidationRules().Single());
            Assert.Equal(
                "RequiredIfValidator: collecting of client validation rules for Value field failed.",
                e.Message);
            Assert.IsType<ApplicationException>(e.InnerException);
            Assert.Equal(
                "HttpContext not available.",
                e.InnerException.Message);
        }
        public void verify_validators_caching()
        {
            const int testLoops = 10;
            var generatedCode = Enumerable.Repeat(0, 100).Select(x => "true")
                .Aggregate("true", (accumulator, item) => $"({accumulator} && {item} && !false)"); // give the parser some work (deep dive)
            
            var model = new Model();
            var metadata = GetModelMetadata(model, m => m.Value);
            var controllerContext = GetControllerContext();

            var assertThat = new AssertThatAttribute(generatedCode);
            var requiredIf = new RequiredIfAttribute(generatedCode);

            var nonCached = MeasureExecutionTime(() => new AssertThatValidator(metadata, controllerContext, assertThat));
            for (var i = 0; i < testLoops; i++)
            {
                var cached = MeasureExecutionTime(() => new AssertThatValidator(metadata, controllerContext, assertThat));
                Assert.True(nonCached > cached);
            }

            nonCached = MeasureExecutionTime(() => new RequiredIfValidator(metadata, controllerContext, requiredIf));
            for (var i = 0; i < testLoops; i++)
            {
                var cached = MeasureExecutionTime(() => new RequiredIfValidator(metadata, controllerContext, requiredIf));
                Assert.True(nonCached > cached);
            }
        }
        public void throw_when_priority_is_not_provided_but_requested_explicitly()
        {
            var assertThat = new AssertThatAttribute("1!=1");
            var requiredIf = new RequiredIfAttribute("1==1");

            Assert.Null(assertThat.GetPriority());
            Assert.Null(requiredIf.GetPriority());

            var e = Assert.Throws<InvalidOperationException>(() => assertThat.Priority);
            Assert.Equal("The Priority property has not been set. Use the GetPriority method to get the value.", e.Message);
            e = Assert.Throws<InvalidOperationException>(() => requiredIf.Priority);
            Assert.Equal("The Priority property has not been set. Use the GetPriority method to get the value.", e.Message);
        }
        private static void AssertErrorMessage(string input, string assertThatOutput, string requiredIfOutput)
        {
            var assertThat = new AssertThatAttribute("1!=1");
            var requiredIf = new RequiredIfAttribute("1==1");

            var isValid = typeof(ExpressiveAttribute).GetMethod("IsValid", BindingFlags.NonPublic | BindingFlags.Instance);
            var context = new ValidationContext(new MsgModel
            {
                Value1 = 0,
                Internal = new MsgModel
                {
                    Value1 = 1,
                    Internal = new MsgModel {Value1 = 2}
                }
            })
            {
                MemberName = "Value1"
            };

            if (input != null)
                assertThat.ErrorMessage = requiredIf.ErrorMessage = input;

            var assertThatResult = (ValidationResult) isValid.Invoke(assertThat, new[] {new object(), context});
            var requiredIfResult = (ValidationResult) isValid.Invoke(requiredIf, new[] {null, context});

            Assert.Equal(assertThatOutput, assertThatResult.ErrorMessage);
            Assert.Equal(requiredIfOutput, requiredIfResult.ErrorMessage);
        }
        public void verify_retrieval_of_correct_member_names_when_validation_context_is_broken()
        {
            var model = new HackTestModel();
            var attrib = new AssertThatAttribute("false");

            // correct path:
            Assert.Equal("Value1", GetFinalMemberName(attrib, model, 0, "Value1", "Value1"));
            Assert.Equal("Value2", GetFinalMemberName(attrib, model, 0, "Value2", "Value 2"));
            Assert.Equal("Value3", GetFinalMemberName(attrib, model, 0, "Value3", "Value 3"));

            // first issue: no member name provided (MVC <= 4)
            Assert.Equal("Value1", GetFinalMemberName(attrib, model, 0, null, "Value1"));
            Assert.Equal("Value2", GetFinalMemberName(attrib, model, 0, null, "Value 2"));
            Assert.Equal("Value3", GetFinalMemberName(attrib, model, 0, null, "Value 3"));

            // second issue: member name equals to display name (WebAPI 2)
            Assert.Equal("Value2", GetFinalMemberName(attrib, model, 0, "Value 2", "Value 2"));
            Assert.Equal("Value3", GetFinalMemberName(attrib, model, 0, "Value 3", "Value 3"));
        }
        public void verify_format_exceptions_from_incorrect_custom_format_specifiers()
        {
            new[]
            {
                "{{field}", "{{field.field}", "{field}}", "{field.field}}",
                "{{field:n}", "{{field.field:n}", "{field:N}}", "{field.field:N}}"
            }.ToList().ForEach(msg =>
            {
                var attrib = new AssertThatAttribute("true") {ErrorMessage = msg};
                var e = Assert.Throws<FormatException>(() => attrib.FormatErrorMessage("asd", "true", null));
                Assert.Equal($"Problem with error message processing. The message is following: {msg}", e.Message);
                Assert.IsType<FormatException>(e.InnerException);
                Assert.Equal("Input string was not in a correct format.", e.InnerException.Message);

                IDictionary<string, Guid> errFieldsMap;
                e = Assert.Throws<FormatException>(() => attrib.FormatErrorMessage("asd", "true", typeof(object), out errFieldsMap));
                Assert.Equal($"Problem with error message processing. The message is following: {msg}", e.Message);
                Assert.IsType<FormatException>(e.InnerException);
                Assert.Equal("Input string was not in a correct format.", e.InnerException.Message);
            });
        }
        public void verify_attributes_identification()
        {
            var assertThat = new AssertThatAttribute("1 !=    1"); // spaces on purpose
            var requiredIf = new RequiredIfAttribute("1 ==    1");

            const string assertThatRepresentation = "ExpressiveAnnotations.Attributes.AssertThatAttribute[1!=1]";
            const string requiredIfRepresentation = "ExpressiveAnnotations.Attributes.RequiredIfAttribute[1==1]";

            Assert.Equal(assertThatRepresentation, assertThat.TypeId);
            Assert.Equal(requiredIfRepresentation, requiredIf.TypeId);

            Assert.Equal(assertThatRepresentation, assertThat.ToString());
            Assert.Equal(requiredIfRepresentation, requiredIf.ToString());

            Assert.Equal(assertThatRepresentation.GetHashCode(), assertThat.GetHashCode());
            Assert.Equal(requiredIfRepresentation.GetHashCode(), requiredIf.GetHashCode());
        }
        public void verify_attributes_equality()
        {
            var assertThat = new AssertThatAttribute("1 !=    1");
            var requiredIf = new RequiredIfAttribute("1 ==    1");

            var assertThat2 = new AssertThatAttribute("1    != 1");
            var requiredIf2 = new RequiredIfAttribute("1    == 1");

            Assert.True(assertThat.Equals(assertThat2));
            Assert.True(requiredIf.Equals(requiredIf2));

            Assert.False(assertThat.Equals(null));
            Assert.False(requiredIf.Equals(null));
        }