diff --git a/HttpAbstractions.sln b/HttpAbstractions.sln index be895cf892..81c1feee17 100644 --- a/HttpAbstractions.sln +++ b/HttpAbstractions.sln @@ -37,6 +37,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.FeatureMod EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.PipelineCore.Tests.net45", "test\Microsoft.AspNet.PipelineCore.Tests\Microsoft.AspNet.PipelineCore.Tests.net45.csproj", "{00A03235-B248-4079-A7EE-4F77AB3A84E4}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.AspNet.Abstractions.Tests.net45", "test\Microsoft.AspNet.Abstractions.Tests\Microsoft.AspNet.Abstractions.Tests.net45.csproj", "{EE4DFB8C-FDD8-4A6E-97B7-AE6E663EE5D0}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -91,6 +93,10 @@ Global {00A03235-B248-4079-A7EE-4F77AB3A84E4}.Debug|Any CPU.Build.0 = Debug|Any CPU {00A03235-B248-4079-A7EE-4F77AB3A84E4}.Release|Any CPU.ActiveCfg = Release|Any CPU {00A03235-B248-4079-A7EE-4F77AB3A84E4}.Release|Any CPU.Build.0 = Release|Any CPU + {EE4DFB8C-FDD8-4A6E-97B7-AE6E663EE5D0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {EE4DFB8C-FDD8-4A6E-97B7-AE6E663EE5D0}.Debug|Any CPU.Build.0 = Debug|Any CPU + {EE4DFB8C-FDD8-4A6E-97B7-AE6E663EE5D0}.Release|Any CPU.ActiveCfg = Release|Any CPU + {EE4DFB8C-FDD8-4A6E-97B7-AE6E663EE5D0}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -111,5 +117,6 @@ Global {04077455-D4A2-43AF-ABA2-E68968856E17} = {F31FF137-390C-49BF-A3BD-7C6ED3597C21} {4C82EE1A-9B93-4374-91E0-75476AABF5CD} = {04077455-D4A2-43AF-ABA2-E68968856E17} {00A03235-B248-4079-A7EE-4F77AB3A84E4} = {04077455-D4A2-43AF-ABA2-E68968856E17} + {EE4DFB8C-FDD8-4A6E-97B7-AE6E663EE5D0} = {04077455-D4A2-43AF-ABA2-E68968856E17} EndGlobalSection EndGlobal diff --git a/src/Microsoft.AspNet.Abstractions/PathString.cs b/src/Microsoft.AspNet.Abstractions/PathString.cs index c497d40bf3..07c6de5446 100644 --- a/src/Microsoft.AspNet.Abstractions/PathString.cs +++ b/src/Microsoft.AspNet.Abstractions/PathString.cs @@ -127,6 +127,15 @@ namespace Microsoft.AspNet.Abstractions /// The combined PathString value public PathString Add(PathString other) { + if (HasValue && + other.HasValue && + Value[Value.Length - 1] == '/') + { + // If the path string has a trailing slash and the other string has a leading slash, we need + // to trim one of them. + return new PathString(Value + other.Value.Substring(1)); + } + return new PathString(Value + other.Value); } diff --git a/test/Microsoft.AspNet.Abstractions.Tests/PathStringTests.cs b/test/Microsoft.AspNet.Abstractions.Tests/PathStringTests.cs new file mode 100644 index 0000000000..02ac73736d --- /dev/null +++ b/test/Microsoft.AspNet.Abstractions.Tests/PathStringTests.cs @@ -0,0 +1,51 @@ +using Microsoft.AspNet.Testing; +using Xunit; + +namespace Microsoft.AspNet.Abstractions +{ + public class PathStringTests + { + [Fact] + public void CtorThrows_IfPathDoesNotHaveLeadingSlash() + { + // Act and Assert + ExceptionAssert.ThrowsArgument(() => new PathString("hello"), "value", ""); + } + + [Theory] + [InlineData(null, null)] + [InlineData("", null)] + public void AddPathString_HandlesNullAndEmptyStrings(string appString, string concatString) + { + // Arrange + var appPath = new PathString(appString); + var concatPath = new PathString(concatString); + + // Act + var result = appPath.Add(concatPath); + + // Assert + Assert.False(result.HasValue); + } + + [Theory] + [InlineData("", "/", "/")] + [InlineData("/", null, "/")] + [InlineData("/", "", "/")] + [InlineData("/", "/test", "/test")] + [InlineData("/myapp/", "/test/bar", "/myapp/test/bar")] + [InlineData("/myapp/", "/test/bar/", "/myapp/test/bar/")] + public void AddPathString_HandlesLeadingAndTrailingSlashes(string appString, string concatString, string expected) + { + // Arrange + var appPath = new PathString(appString); + var concatPath = new PathString(concatString); + + // Act + var result = appPath.Add(concatPath); + + // Assert + Assert.Equal(expected, result.Value); + } + } +} diff --git a/test/Microsoft.AspNet.Abstractions.Tests/project.json b/test/Microsoft.AspNet.Abstractions.Tests/project.json new file mode 100644 index 0000000000..110d62bb6d --- /dev/null +++ b/test/Microsoft.AspNet.Abstractions.Tests/project.json @@ -0,0 +1,23 @@ +{ + "version": "0.1-alpha-*", + "dependencies": { + "Microsoft.AspNet.Abstractions": "", + "Microsoft.AspNet.Testing": "0.1-alpha-*", + "Xunit.KRunner": "0.1-alpha-*", + "xunit.abstractions": "2.0.0-aspnet-*", + "xunit.assert": "2.0.0-aspnet-*", + "xunit.core": "2.0.0-aspnet-*", + "xunit.execution": "2.0.0-aspnet-*" + }, + "commands": { + "test": "Xunit.KRunner" + }, + "configurations": { + "net45": { + "dependencies": { + "System.Runtime": "", + "Shouldly": "1.1.1.1" + } + } + } +} \ No newline at end of file