Adds mod_rewrite tests, small refactors to exception messages and types

This commit is contained in:
Justin Kotalik 2016-08-18 16:15:17 -07:00
parent d1ab35db87
commit 73e0d531e0
8 changed files with 238 additions and 26 deletions

View File

@ -77,7 +77,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
FlagType flag;
if (!_ruleFlagLookup.TryGetValue(hasPayload[0], out flag))
{
throw new FormatException($"Unrecognized flag: {hasPayload[0]}");
throw new FormatException($"Unrecognized flag: '{hasPayload[0]}'");
}
if (hasPayload.Length == 2)

View File

@ -146,7 +146,7 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
else
{
// illegal escape of a character
throw new FormatException(Resources.FormatError_InputParserUnrecognizedParameter(context.Template, context.Index));
throw new FormatException(Resources.FormatError_InputParserInvalidInteger(context.Template, context.Index));
}
}

View File

@ -29,27 +29,19 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
return null;
}
var context = new ParserContext(rule);
if (!context.Next())
{
return null;
}
context.Next();
var tokens = new List<string>();
context.Mark();
while (true)
{
if (!context.Next())
{
// End of string. Capture.
break;
}
else if (context.Current == Escape)
if (context.Current == Escape)
{
// Need to progress such that the next character is not evaluated.
if (!context.Next())
{
// Means that a character was not escaped appropriately Ex: "foo\"
throw new FormatException("Invalid escaper character in string " + rule);
throw new FormatException($"Invalid escaper character in string: {rule}");
}
}
else if (context.Current == Space || context.Current == Tab)
@ -68,14 +60,21 @@ namespace Microsoft.AspNetCore.Rewrite.Internal.ModRewrite
}
}
context.Mark();
context.Back();
}
}
if (!context.Next())
{
// End of string. Capture.
break;
}
}
var done = context.Capture();
if (!string.IsNullOrEmpty(done))
{
tokens.Add(done);
}
return tokens;
}
}

View File

@ -1,12 +1,13 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite;
using Xunit;
namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
{
public class ConditionActionTest
public class ConditionPatternParserTest
{
[Theory]
[InlineData(">hey", OperationType.Greater, "hey", ConditionType.StringComp)]
@ -14,7 +15,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
[InlineData(">=hey", OperationType.GreaterEqual, "hey", ConditionType.StringComp)]
[InlineData("<=hey", OperationType.LessEqual, "hey", ConditionType.StringComp)]
[InlineData("=hey", OperationType.Equal, "hey", ConditionType.StringComp)]
public void ConditionParser_CheckStringComp(string condition, OperationType operation, string variable, ConditionType conditionType)
public void ConditionPatternParser_CheckStringComp(string condition, OperationType operation, string variable, ConditionType conditionType)
{
var results = new ConditionPatternParser().ParseActionCondition(condition);
@ -23,12 +24,12 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
}
[Fact]
public void ConditionParser_CheckRegexEqual()
public void ConditionPatternParser_CheckRegexEqual()
{
var condition = @"(.*)";
var results = new ConditionPatternParser().ParseActionCondition(condition);
var expected = new ParsedModRewriteInput { ConditionType = ConditionType.Regex, Operand = "(.*)", Invert = false };
var expected = new ParsedModRewriteInput { ConditionType = ConditionType.Regex, Operand = "(.*)", Invert = false };
Assert.True(CompareConditions(results, expected));
}
@ -42,11 +43,11 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
[InlineData("-s", OperationType.Size, ConditionType.PropertyTest)]
[InlineData("-U", OperationType.ExistingUrl, ConditionType.PropertyTest)]
[InlineData("-x", OperationType.Executable, ConditionType.PropertyTest)]
public void ConditionParser_CheckFileOperations(string condition, OperationType operation, ConditionType cond)
public void ConditionPatternParser_CheckFileOperations(string condition, OperationType operation, ConditionType cond)
{
var results = new ConditionPatternParser().ParseActionCondition(condition);
var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation , Invert = false };
var expected = new ParsedModRewriteInput { ConditionType = cond, OperationType = operation, Invert = false };
Assert.True(CompareConditions(results, expected));
}
@ -60,7 +61,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
[InlineData("!-s", OperationType.Size, ConditionType.PropertyTest)]
[InlineData("!-U", OperationType.ExistingUrl, ConditionType.PropertyTest)]
[InlineData("!-x", OperationType.Executable, ConditionType.PropertyTest)]
public void ConditionParser_CheckFileOperationsInverted(string condition, OperationType operation, ConditionType cond)
public void ConditionPatternParser_CheckFileOperationsInverted(string condition, OperationType operation, ConditionType cond)
{
var results = new ConditionPatternParser().ParseActionCondition(condition);
@ -75,7 +76,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
[InlineData("-le1", OperationType.LessEqual, "1", ConditionType.IntComp)]
[InlineData("-eq1", OperationType.Equal, "1", ConditionType.IntComp)]
[InlineData("-ne1", OperationType.NotEqual, "1", ConditionType.IntComp)]
public void ConditionParser_CheckIntComp(string condition, OperationType operation, string variable, ConditionType cond)
public void ConditionPatternParser_CheckIntComp(string condition, OperationType operation, string variable, ConditionType cond)
{
var results = new ConditionPatternParser().ParseActionCondition(condition);
@ -83,7 +84,22 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
Assert.True(CompareConditions(results, expected));
}
// TODO negative tests
[Theory]
[InlineData("", "Unrecognized parameter type: '', terminated at string index: '0'")]
[InlineData("!", "Unrecognized parameter type: '!', terminated at string index: '1'")]
[InlineData(">", "Unrecognized parameter type: '>', terminated at string index: '1'")]
[InlineData("<", "Unrecognized parameter type: '<', terminated at string index: '1'")]
[InlineData("=", "Unrecognized parameter type: '=', terminated at string index: '1'")]
[InlineData(">=", "Unrecognized parameter type: '>=', terminated at string index: '2'")]
[InlineData("<=", "Unrecognized parameter type: '<=', terminated at string index: '2'")]
[InlineData("-a", "Unrecognized parameter type: '-a', terminated at string index: '1'")]
[InlineData("-gewow", "Unrecognized parameter type: '-gewow', terminated at string index: '3'")]
public void ConditionPatternParser_AssertBadInputThrowsFormatException(string input, string expected)
{
var ex = Assert.Throws<FormatException>(() => new ConditionPatternParser().ParseActionCondition(input));
Assert.Equal(expected, ex.Message);
}
private bool CompareConditions(ParsedModRewriteInput i1, ParsedModRewriteInput i2)
{
if (i1.OperationType != i2.OperationType ||

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite;
@ -47,6 +48,24 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
Assert.True(DictionaryContentsEqual(results.FlagDictionary, expected.FlagDictionary));
}
[Theory]
[InlineData("]", "Flags should start and end with square brackets: [flags]")]
[InlineData("[", "Flags should start and end with square brackets: [flags]")]
[InlineData("[R, L]", "Unrecognized flag: ' L'")] // cannot have spaces after ,
[InlineData("[RL]", "Unrecognized flag: 'RL'")]
public void FlagParser_AssertFormatErrorWhenFlagsArePoorlyConstructed(string input, string expected)
{
var ex = Assert.Throws<FormatException>(() => new FlagParser().Parse(input));
Assert.Equal(expected, ex.Message);
}
[Fact]
public void FlagParser_AssertArgumentExceptionWhenFlagsAreNullOrEmpty()
{
Assert.Throws<ArgumentNullException>(() => new FlagParser().Parse(null));
Assert.Throws<ArgumentNullException>(() => new FlagParser().Parse(string.Empty));
}
public bool DictionaryContentsEqual<TKey, TValue>(IDictionary<TKey, TValue> dictionary, IDictionary<TKey, TValue> other)
{
return (other ?? new Dictionary<TKey, TValue>())

View File

@ -11,7 +11,7 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
public class FormatExceptionTests
{
[Theory]
[InlineData(@"RewriteCond 1 2\", @"Invalid escaper character in string RewriteCond 1 2\")]
[InlineData(@"RewriteCond 1 2\", @"Invalid escaper character in string: RewriteCond 1 2\")]
[InlineData("BadExpression 1 2 3 4", "Could not parse the mod_rewrite file. Message: 'Too many tokens on line'. Line number '1'.")]
[InlineData("RewriteCond % 2", "Could not parse the mod_rewrite file. Line number '1'.")]
[InlineData("RewriteCond %{ 2", "Could not parse the mod_rewrite file. Line number '1'.")]

View File

@ -1,6 +1,7 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite;
using Xunit;
@ -31,9 +32,45 @@ namespace Microsoft.AspNetCore.Rewrite.Tests.ModRewrite
var expected = new List<string>();
expected.Add("RewriteCond");
expected.Add(@"%{HTTPS}\ what"); // TODO maybe just have the space here? talking point
expected.Add(@"%{HTTPS}\ what");
expected.Add("!-f");
Assert.Equal(tokens,expected);
Assert.Equal(tokens, expected);
}
[Fact]
public void Tokenize_CheckWhiteSpaceDirectlyFollowedByEscapeCharacter_CorrectSplit()
{
var testString = @"RewriteCond %{HTTPS} \ what !-f";
var tokens = new Tokenizer().Tokenize(testString);
var expected = new List<string>();
expected.Add(@"RewriteCond");
expected.Add(@"%{HTTPS}");
expected.Add(@"\ what");
expected.Add(@"!-f");
Assert.Equal(tokens, expected);
}
[Fact]
public void Tokenize_CheckWhiteSpaceAtEndOfString_CorrectSplit()
{
var testString = @"RewriteCond %{HTTPS} \ what !-f ";
var tokens = new Tokenizer().Tokenize(testString);
var expected = new List<string>();
expected.Add(@"RewriteCond");
expected.Add(@"%{HTTPS}");
expected.Add(@"\ what");
expected.Add(@"!-f");
Assert.Equal(expected, tokens);
}
[Fact]
public void Tokenize_AssertFormatExceptionWhenEscapeCharacterIsAtEndOfString()
{
var ex = Assert.Throws<FormatException>(() => new Tokenizer().Tokenize("\\"));
Assert.Equal(@"Invalid escaper character in string: \", ex.Message);
}
}
}

View File

@ -0,0 +1,141 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Rewrite.Internal;
using Microsoft.AspNetCore.Rewrite.Internal.ModRewrite;
using Microsoft.AspNetCore.Rewrite.Internal.PatternSegments;
using Xunit;
namespace Microsoft.AspNetCore.Rewrite
{
public class TestStringParserTests
{
[Fact]
public void ConditionParser_SingleServerVariable()
{
var serverVar = "%{HTTPS}";
var result = new TestStringParser().Parse(serverVar);
var list = new List<PatternSegment>();
list.Add(new IsHttpsModSegment());
var expected = new Pattern(list);
AssertPatternsEqual(expected, result);
}
[Fact]
public void ConditionParser_MultipleServerVariables()
{
var serverVar = "%{HTTPS}%{REQUEST_URI}";
var result = new TestStringParser().Parse(serverVar);
var list = new List<PatternSegment>();
list.Add(new IsHttpsModSegment());
list.Add(new UrlSegment());
var expected = new Pattern(list);
AssertPatternsEqual(expected, result);
}
[Fact]
public void ConditionParser_ParseLiteral()
{
var serverVar = "Hello!";
var result = new TestStringParser().Parse(serverVar);
var list = new List<PatternSegment>();
list.Add(new LiteralSegment(serverVar));
var expected = new Pattern(list);
AssertPatternsEqual(expected, result);
}
[Fact]
public void ConditionParser_ParseConditionParameters()
{
var serverVar = "%1";
var result = new TestStringParser().Parse(serverVar);
var list = new List<PatternSegment>();
list.Add(new ConditionMatchSegment(1));
var expected = new Pattern(list);
AssertPatternsEqual(expected, result);
}
[Fact]
public void ConditionParser_ParseMultipleConditionParameters()
{
var serverVar = "%1%2";
var result = new TestStringParser().Parse(serverVar);
var list = new List<PatternSegment>();
list.Add(new ConditionMatchSegment(1));
list.Add(new ConditionMatchSegment(2));
var expected = new Pattern(list);
AssertPatternsEqual(expected, result);
}
[Fact]
public void ConditionParser_ParseRuleVariable()
{
var serverVar = "$1";
var result = new TestStringParser().Parse(serverVar);
var list = new List<PatternSegment>();
list.Add(new RuleMatchSegment(1));
var expected = new Pattern(list);
AssertPatternsEqual(expected, result);
}
[Fact]
public void ConditionParser_ParseMultipleRuleVariables()
{
var serverVar = "$1$2";
var result = new TestStringParser().Parse(serverVar);
var list = new List<PatternSegment>();
list.Add(new RuleMatchSegment(1));
list.Add(new RuleMatchSegment(2));
var expected = new Pattern(list);
AssertPatternsEqual(expected, result);
}
[Fact]
public void ConditionParser_ParserComplexRequest()
{
var serverVar = "%{HTTPS}/$1";
var result = new TestStringParser().Parse(serverVar);
var list = new List<PatternSegment>();
list.Add(new IsHttpsModSegment());
list.Add(new LiteralSegment("/"));
list.Add(new RuleMatchSegment(1));
var expected = new Pattern(list);
AssertPatternsEqual(expected, result);
}
[Theory]
[InlineData(@"%}", "Cannot parse '%}' to integer at string index: '1'")] // no } at end
[InlineData(@"%{", "Missing close brace for parameter at string index: '2'")] // no closing }
[InlineData(@"%a", "Cannot parse '%a' to integer at string index: '1'")] // invalid character after %
[InlineData(@"$a", "Cannot parse '$a' to integer at string index: '1'")] // invalid character after $
[InlineData(@"%{asdf", "Missing close brace for parameter at string index: '6'")] // no closing } with characters
public void ConditionParser_Bad(string testString, string expected)
{
var ex = Assert.Throws<FormatException>(() => new TestStringParser().Parse(testString));
Assert.Equal(ex.Message, expected);
}
private void AssertPatternsEqual(Pattern p1, Pattern p2)
{
Assert.Equal(p1.PatternSegments.Count, p2.PatternSegments.Count);
for (int i = 0; i < p1.PatternSegments.Count; i++)
{
var s1 = p1.PatternSegments[i];
var s2 = p2.PatternSegments[i];
Assert.Equal(s1.GetType(), s2.GetType());
}
}
}
}