Added unit test project. Improved route matcher and fixed bugs.

This commit is contained in:
2022-03-03 00:18:45 -08:00
parent 16c42c1ef7
commit da8184f152
5 changed files with 238 additions and 69 deletions

View File

@@ -17,8 +17,8 @@ namespace MontoyaTech.Rest.Net
/// ** = anything from this point forward is accepted
/// {} = route parameter
/// ! = must not match
/// || = logical or
/// && = logical and
/// | = logical or
/// & = logical and
///
/// Note:
/// If route parameter doesn't end with /, then the parameter will be the rest of the url.
@@ -37,6 +37,18 @@ namespace MontoyaTech.Rest.Net
url = url.Trim();
syntax = syntax.Trim();
//If the url starts with http or https remove that so we just have the path left.
if (url.StartsWith("http://"))
{
url = url.Substring(7);
url = url.Substring(url.IndexOf('/'));
}
else if (url.StartsWith("https://"))
{
url = url.Substring(8);
url = url.Substring(url.IndexOf('/'));
}
//Split the url and the syntax into path segments
var urlSegments = url.Split('/').Where(segment => segment.Length > 0).Select(segment => segment.Trim()).ToArray();
var syntaxSegments = syntax.Split('/').Where(segment => segment.Length > 0).Select(segment => segment.Trim()).ToArray();
@@ -47,10 +59,10 @@ namespace MontoyaTech.Rest.Net
//If we have no syntax segments this is not a match.
else if (syntaxSegments.Length == 0)
return false;
//If we have segments and the url does not then this may not be a match.
if (urlSegments.Length == 0 && syntaxSegments[0] == "**")
//If the url has no segments but the syntax is a double wild card then this is a match.
else if (urlSegments.Length == 0 && syntaxSegments[0] == "**")
return true;
//If the url has no segments but the syntax is a wildcard then this is a match.
else if (urlSegments.Length == 0 && syntaxSegments.Length == 1 && syntaxSegments[0] == "*")
return true;
@@ -64,26 +76,71 @@ namespace MontoyaTech.Rest.Net
{
var syntaxSegment = syntaxSegments[i];
var urlSegment = urlSegments[i];
//If the segments syntax is a double wild card then everything after this is a match.
if (syntaxSegment == "**")
{
return true;
}
else if (syntaxSegment.StartsWith("{") && syntaxSegment.EndsWith("}") && i + 1 >= syntaxSegments.Length && syntax.EndsWith("/") == false)
else
{
//Special case, syntax ends with a parameter, so recombine the rest of the url and add it as a parameter.
var key = syntaxSegment.Substring(1, syntaxSegment.Length - 2);
var conditions = new List<string>();
var builder = new StringBuilder();
for (int c = 0; c < syntaxSegment.Length; c++)
{
if (syntaxSegment[c] == '|' || syntaxSegment[c] == '&')
{
conditions.Add(builder.ToString());
conditions.Add(syntaxSegment[c].ToString());
builder.Clear();
}
else if (syntaxSegment[c] != ' ')
{
builder.Append(syntaxSegment[c]);
}
}
for (int i2 = i; i2 < urlSegments.Length; i2++)
builder.Append(urlSegments[i2]).Append(i2 + 1 < urlSegments.Length ? "/" : "");
if (builder.Length > 0)
conditions.Add(builder.ToString());
arguments[argumentIndex++] = builder.ToString();
bool match = false;
foreach (var condition in conditions)
{
if (condition == "*")
{
match = true;
}
else if (condition == "**")
{
match = true;
}
else if (condition.StartsWith("!") && condition.Substring(1) != urlSegment)
{
match = true;
}
else if (condition.StartsWith("{") && condition.EndsWith("}"))
{
arguments[argumentIndex++] = urlSegment;
return true;
}
else if (SegmentMatches(urlSegments[i], syntaxSegment, arguments, ref argumentIndex) == false)
{
return false;
match = true;
}
else if (condition == "&" && !match)
{
break;
}
else if (condition == "|" && match)
{
break;
}
else if (condition == urlSegment)
{
match = true;
}
}
if (!match)
return false;
}
}
@@ -94,58 +151,5 @@ namespace MontoyaTech.Rest.Net
else
return true;
}
private static bool SegmentMatches(string segment, string syntax, string[] arguments, ref int argumentIndex)
{
//Split the syntax into conditions
string[] conditions = syntax.Split(' ').Where(condition => condition.Length > 0).ToArray();
//Based off the matches, see if the segment matches.
bool match = false;
for (int i = 0; i < conditions.Length; i++)
{
var condition = conditions[i];
if (condition == "*")
{
match = true;
}
else if (condition == "**")
{
return true;
}
else if (condition.StartsWith("!"))
{
if (condition.Substring(1) == segment)
match = false;
else
match = true;
}
else if (condition.StartsWith("{") && condition.EndsWith("}"))
{
var key = condition.Substring(1, condition.Length - 2);
arguments[argumentIndex++] = segment;
match = true;
}
else if (condition == "&&")
{
if (match == false)
return false;
}
else if (condition == "||")
{
if (match)
return true;
}
else if (condition == segment)
{
return true;
}
}
return match;
}
}
}