diff --git a/FluentUriBuilder.sln b/FluentUriBuilder.sln index 8a52910..653003c 100644 --- a/FluentUriBuilder.sln +++ b/FluentUriBuilder.sln @@ -12,6 +12,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FluentUriBuilder", "src\FluentUriBuilder\FluentUriBuilder.xproj", "{F6EA52B1-1BC1-490B-A348-87E83C63F24B}" EndProject +Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FluentUriBuilder.Tests", "src\FluentUriBuilder.Tests\FluentUriBuilder.Tests.xproj", "{ECACA676-2599-4FA5-8E25-7503F0CCCA78}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -22,11 +24,16 @@ Global {F6EA52B1-1BC1-490B-A348-87E83C63F24B}.Debug|Any CPU.Build.0 = Debug|Any CPU {F6EA52B1-1BC1-490B-A348-87E83C63F24B}.Release|Any CPU.ActiveCfg = Release|Any CPU {F6EA52B1-1BC1-490B-A348-87E83C63F24B}.Release|Any CPU.Build.0 = Release|Any CPU + {ECACA676-2599-4FA5-8E25-7503F0CCCA78}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {ECACA676-2599-4FA5-8E25-7503F0CCCA78}.Debug|Any CPU.Build.0 = Debug|Any CPU + {ECACA676-2599-4FA5-8E25-7503F0CCCA78}.Release|Any CPU.ActiveCfg = Release|Any CPU + {ECACA676-2599-4FA5-8E25-7503F0CCCA78}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution {F6EA52B1-1BC1-490B-A348-87E83C63F24B} = {F9CD17B2-71B0-4193-8028-541403725E0D} + {ECACA676-2599-4FA5-8E25-7503F0CCCA78} = {F9CD17B2-71B0-4193-8028-541403725E0D} EndGlobalSection EndGlobal diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..e8feb4d --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,5 @@ +version: 1.0.{build} +before_build: +- ps: nuget restore +build: + verbosity: minimal \ No newline at end of file diff --git a/src/FluentUriBuilder.Tests/ExtensionTests.cs b/src/FluentUriBuilder.Tests/ExtensionTests.cs new file mode 100644 index 0000000..2aea347 --- /dev/null +++ b/src/FluentUriBuilder.Tests/ExtensionTests.cs @@ -0,0 +1,102 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace FluentUriBuilder.Tests +{ + public class ExtensionTests + { + [Theory] + [InlineData("/awesome", "awesome")] + [InlineData("/////awesome", "awesome")] + [InlineData("awesome/", "awesome/")] + public void PathDoesNotGetMultipleAppends(string pathWithSlashes, string expectedPath) + { + var url = new UriBuilder("http://awesome.com") + .WithPathSegment(pathWithSlashes); + Assert.Equal("http://awesome.com/" + expectedPath, url.Uri.ToString()); + } + + [Fact] + public void MultiplePathSegementsWork() + { + var url = new UriBuilder("http://awesome.com") + .WithPathSegment("yodawg") + .WithPathSegment("/immahslash/"); + Assert.Equal("http://awesome.com/yodawg/immahslash/", url.Uri.ToString()); + } + + [Fact] + public void TestAddUrlParameter() + { + var url = new UriBuilder("http://awesome.com") + .WithParameter("awesome", "yodawg"); + Assert.Equal("http://awesome.com/?awesome=yodawg", url.Uri.ToString()); + } + + [Fact] + public void TestAddParameterArray() + { + var url = new UriBuilder("http://awesome.com") + .WithParameter("awesome", "cool", "dawg"); + Assert.Equal("http://awesome.com/?awesome=cool,dawg", url.Uri.ToString()); + } + + [Fact] + public void TestAddParameterNoValue() + { + var url = new UriBuilder("http://awesome.com") + .WithParameter("awesome"); + Assert.Equal("http://awesome.com/?awesome", url.Uri.ToString()); + } + + [Fact] + public void WithPort() + { + var url = new UriBuilder().WithPort(22); + Assert.Equal(url.Port, 22); + } + + [Fact] + public void WithHttps() + { + var url = new UriBuilder().UseHttps(true); + Assert.Equal(url.Scheme, "https"); + } + + [Fact] + public void WithHttp() + { + var url = new UriBuilder().UseHttps(false); + Assert.Equal(url.Scheme, "http"); + } + + [Fact] + public void WithScheme() + { + //the jesus scheme? + var url = new UriBuilder().WithScheme("jesus"); + Assert.Equal(url.Scheme, "jesus"); + } + + [Fact] + public void WithHost() + { + //the jesus scheme? + var url = new UriBuilder().WithHost("yodawg.com"); + Assert.Equal(url.Host, "yodawg.com"); + } + + [Fact] + public void TestAddTwoUrlParameters() + { + var url = new UriBuilder("http://awesome.com") + .WithParameter("awesome", "yodawg") + .WithParameter("supg", "no2") + .WithParameter("supgf", "no22"); + Assert.Equal("http://awesome.com/?awesome=yodawg&supg=no2&supgf=no22", url.Uri.ToString()); + } + } +} \ No newline at end of file diff --git a/src/FluentUriBuilder.Tests/FluentUriBuilder.Tests.xproj b/src/FluentUriBuilder.Tests/FluentUriBuilder.Tests.xproj new file mode 100644 index 0000000..c661151 --- /dev/null +++ b/src/FluentUriBuilder.Tests/FluentUriBuilder.Tests.xproj @@ -0,0 +1,22 @@ + + + + 14.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + + ecaca676-2599-4fa5-8e25-7503f0ccca78 + FluentUriBuilder.Tests + .\obj + .\bin\ + v4.5.2 + + + 2.0 + + + + + + \ No newline at end of file diff --git a/src/FluentUriBuilder.Tests/Properties/AssemblyInfo.cs b/src/FluentUriBuilder.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..c129c66 --- /dev/null +++ b/src/FluentUriBuilder.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,19 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("FluentUriBuilder.Tests")] +[assembly: AssemblyTrademark("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ecaca676-2599-4fa5-8e25-7503f0ccca78")] diff --git a/src/FluentUriBuilder.Tests/ThrowsTests.cs b/src/FluentUriBuilder.Tests/ThrowsTests.cs new file mode 100644 index 0000000..012070c --- /dev/null +++ b/src/FluentUriBuilder.Tests/ThrowsTests.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Xunit; + +namespace FluentUriBuilder.Tests +{ + public class ThrowsTests + { + [Fact] + public void ThrowsArgNull() + { + var tstObj = new UriBuilder(); + Assert.Throws(() => tstObj.WithParameter(string.Empty, string.Empty)); + Assert.Throws(() => tstObj.WithPathSegment(null)); + Assert.Throws(() => tstObj.WithScheme(null)); + Assert.Throws(() => tstObj.WithHost(null)); + Assert.Throws(() => tstObj.WithPort(-1)); + } + } +} \ No newline at end of file diff --git a/src/FluentUriBuilder.Tests/project.json b/src/FluentUriBuilder.Tests/project.json new file mode 100644 index 0000000..968d271 --- /dev/null +++ b/src/FluentUriBuilder.Tests/project.json @@ -0,0 +1,21 @@ +{ + "version": "1.0.0-*", + "testRunner": "xunit", + + "dependencies": { + "xunit": "2.2.0-beta2-build3300", + "dotnet-test-xunit": "2.2.0-preview2-build1029", + "FluentUriBuilder": "*" + }, + + "frameworks": { + "netcoreapp1.0": { + "dependencies": { + "Microsoft.NETCore.App": { + "type": "platform", + "version": "1.0.0" + } + } + } + } +} \ No newline at end of file diff --git a/src/FluentUriBuilder/TerribleDevUriExtensions.cs b/src/FluentUriBuilder/TerribleDevUriExtensions.cs index 790b80c..66fcc3b 100644 --- a/src/FluentUriBuilder/TerribleDevUriExtensions.cs +++ b/src/FluentUriBuilder/TerribleDevUriExtensions.cs @@ -8,35 +8,28 @@ namespace System { public static class TerribleDevUriExtensions { - public static UriBuilder WithParameter(this UriBuilder bld, string key, string value) + public static UriBuilder WithParameter(this UriBuilder bld, string key, params string[] values) { if(string.IsNullOrWhiteSpace(key)) { throw new ArgumentNullException(nameof(key)); } - if(string.IsNullOrWhiteSpace(value)) + if(values == null) { - throw new ArgumentNullException(nameof(value)); + values = new string[0]; } - if(!string.IsNullOrWhiteSpace(bld.Query)) - { - bld.Query += $"&{key}={value}"; - return bld; - } - bld.Query = $"{key}={value}"; - return bld; - } - - public static UriBuilder WithParameter(this UriBuilder bld, string key, IEnumerable values) - { var isfirst = string.IsNullOrWhiteSpace(bld.Query); - var intitialValue = isfirst ? "?" : $"{bld.Query}& "; - var sb = new StringBuilder($"{intitialValue}{key}="); + var intitialValue = isfirst ? "?" : $"{bld.Query}&"; + var sb = new StringBuilder($"{intitialValue}{key}"); + var validValueHit = false; foreach(var value in values) { var toSValue = value?.ToString(); if(string.IsNullOrWhiteSpace(toSValue)) continue; - sb.Append($"{value},"); + // we can't just have an = sign since its valid to have query string paramters with no value; + if(!validValueHit) toSValue = "=" + value; + validValueHit = true; + sb.Append($"{toSValue},"); } bld.Query = sb.ToString().TrimEnd(','); return bld; @@ -51,6 +44,10 @@ namespace System public static UriBuilder WithPathSegment(this UriBuilder bld, string pathSegment) { + if(string.IsNullOrWhiteSpace(pathSegment)) + { + throw new ArgumentNullException(nameof(pathSegment)); + } var path = pathSegment.TrimStart('/'); if(string.IsNullOrWhiteSpace(bld.Path)) { @@ -77,7 +74,7 @@ namespace System public static UriBuilder UseHttps(this UriBuilder bld, bool predicate = true) { - if(predicate) bld.Scheme = "https"; + bld.Scheme = predicate ? "https" : "http"; return bld; } }