public void ParseRouteParameter_ThrowsIf_ParameterContainsSpecialCharacters(string template, string expectedMessage)
        {
            // Act & Assert
            var ex = Assert.Throws <InvalidOperationException>(() => LegacyTemplateParser.ParseTemplate(template));

            Assert.Equal(expectedMessage, ex.Message);
        }
        public void InvalidTemplate_WithMismatchedBraces(string template, string expectedMessage)
        {
            var ex = Assert.Throws <InvalidOperationException>(
                () => LegacyTemplateParser.ParseTemplate(template));

            Assert.Equal(expectedMessage, ex.Message);
        }
        public void InvalidTemplate_BadOptionalCharacterPosition()
        {
            var ex = Assert.Throws <ArgumentException>(() => LegacyTemplateParser.ParseTemplate("/test/{a?bc}/{b}"));

            var expectedMessage = "Malformed parameter 'a?bc' in route '/test/{a?bc}/{b}'. '?' character can only appear at the end of parameter name.";

            Assert.Equal(expectedMessage, ex.Message);
        }
        public void InvalidTemplate_CatchAllParamNotLast()
        {
            var ex = Assert.Throws <InvalidOperationException>(() => LegacyTemplateParser.ParseTemplate("/test/{*a}/{b}"));

            var expectedMessage = "Invalid template 'test/{*a}/{b}'. A catch-all parameter can only appear as the last segment of the route template.";

            Assert.Equal(expectedMessage, ex.Message);
        }
        public void InvalidTemplate_CatchAllParamWithMultipleAsterisks()
        {
            var ex = Assert.Throws <InvalidOperationException>(() => LegacyTemplateParser.ParseTemplate("/test/{a}/{**b}"));

            var expectedMessage = "Invalid template '/test/{a}/{**b}'. A catch-all parameter may only have one '*' at the beginning of the segment.";

            Assert.Equal(expectedMessage, ex.Message);
        }
        public void InvalidTemplate_NonOptionalParamAfterOptionalParam()
        {
            var ex = Assert.Throws <InvalidOperationException>(() => LegacyTemplateParser.ParseTemplate("/test/{a?}/{b}"));

            var expectedMessage = "Invalid template 'test/{a?}/{b}'. Non-optional parameters or literal routes cannot appear after optional parameters.";

            Assert.Equal(expectedMessage, ex.Message);
        }
        public void InvalidTemplate_ConsecutiveSeparatorsSlashSlashThrows()
        {
            var ex = Assert.Throws <InvalidOperationException>(() => LegacyTemplateParser.ParseTemplate("{a}//{z}"));

            var expectedMessage = "Invalid template '{a}//{z}'. Empty segments are not allowed.";

            Assert.Equal(expectedMessage, ex.Message);
        }
        public void InvalidTemplate_InvalidParameterNameWithEmptyNameThrows()
        {
            var ex = Assert.Throws <InvalidOperationException>(() => LegacyTemplateParser.ParseTemplate("{a}/{}/{z}"));

            var expectedMessage = "Invalid template '{a}/{}/{z}'. Empty parameter name in segment '{}' is not allowed.";

            Assert.Equal(expectedMessage, ex.Message);
        }
        public void InvalidTemplate_WithRepeatedParameter()
        {
            var ex = Assert.Throws <InvalidOperationException>(
                () => LegacyTemplateParser.ParseTemplate("{p1}/literal/{p1}"));

            var expectedMessage = "Invalid template '{p1}/literal/{p1}'. The parameter 'Microsoft.AspNetCore.Components.LegacyRouteMatching.LegacyTemplateSegment' appears multiple times.";

            Assert.Equal(expectedMessage, ex.Message);
        }
        public void Parse_MixedLiteralAndCatchAllParameter()
        {
            // Arrange
            var expected = new ExpectedTemplateBuilder().Literal("awesome").Literal("wow").Parameter("p");

            // Act
            var actual = LegacyTemplateParser.ParseTemplate("awesome/wow/{*p}");

            // Assert
            Assert.Equal(expected, actual, LegacyRouteTemplateTestComparer.Instance);
        }
        public void Parse_SingleCatchAllParameter()
        {
            // Arrange
            var expected = new ExpectedTemplateBuilder().Parameter("p");

            // Act
            var actual = LegacyTemplateParser.ParseTemplate("{*p}");

            // Assert
            Assert.Equal(expected, actual, LegacyRouteTemplateTestComparer.Instance);
        }
        public void Parse_SingleLiteral()
        {
            // Arrange
            var expected = new ExpectedTemplateBuilder().Literal("awesome");

            // Act
            var actual = LegacyTemplateParser.ParseTemplate("awesome");

            // Assert
            Assert.Equal(expected, actual, LegacyRouteTemplateTestComparer.Instance);
        }
        public void Parse_MultipleOptionalParameters()
        {
            // Arrange
            var template = "{p1?}/{p2?}/{p3?}";

            var expected = new ExpectedTemplateBuilder().Parameter("p1?").Parameter("p2?").Parameter("p3?");

            // Act
            var actual = LegacyTemplateParser.ParseTemplate(template);

            // Assert
            Assert.Equal(expected, actual, LegacyRouteTemplateTestComparer.Instance);
        }
        public void Parse_MultipleLiterals()
        {
            // Arrange
            var template = "awesome/cool/super";

            var expected = new ExpectedTemplateBuilder().Literal("awesome").Literal("cool").Literal("super");

            // Act
            var actual = LegacyTemplateParser.ParseTemplate(template);

            // Assert
            Assert.Equal(expected, actual, LegacyRouteTemplateTestComparer.Instance);
        }
        internal static LegacyRouteTable Create(Dictionary <Type, string[]> templatesByHandler)
        {
            var routes = new List <LegacyRouteEntry>();

            foreach (var keyValuePair in templatesByHandler)
            {
                var parsedTemplates        = keyValuePair.Value.Select(v => LegacyTemplateParser.ParseTemplate(v)).ToArray();
                var allRouteParameterNames = parsedTemplates
                                             .SelectMany(GetParameterNames)
                                             .Distinct(StringComparer.OrdinalIgnoreCase)
                                             .ToArray();

                foreach (var parsedTemplate in parsedTemplates)
                {
                    var unusedRouteParameterNames = allRouteParameterNames
                                                    .Except(GetParameterNames(parsedTemplate), StringComparer.OrdinalIgnoreCase)
                                                    .ToArray();
                    var entry = new LegacyRouteEntry(parsedTemplate, keyValuePair.Key, unusedRouteParameterNames);
                    routes.Add(entry);
                }
            }

            return(new LegacyRouteTable(routes.OrderBy(id => id, RoutePrecedence).ToArray()));
        }