diff --git a/src/AutoRest.CSharp/Common/Output/Expressions/KnownValueExpressions/IntExpression.cs b/src/AutoRest.CSharp/Common/Output/Expressions/KnownValueExpressions/IntExpression.cs index f44eb093bf2..2d249670a08 100644 --- a/src/AutoRest.CSharp/Common/Output/Expressions/KnownValueExpressions/IntExpression.cs +++ b/src/AutoRest.CSharp/Common/Output/Expressions/KnownValueExpressions/IntExpression.cs @@ -8,5 +8,17 @@ namespace AutoRest.CSharp.Common.Output.Expressions.KnownValueExpressions internal sealed record IntExpression(ValueExpression Untyped) : TypedValueExpression(Untyped) { public static IntExpression MaxValue => new(StaticProperty(nameof(int.MaxValue))); + + public IntExpression Add(IntExpression value) => Operator("+", value); + public IntExpression Minus(IntExpression value) => Operator("-", value); + public IntExpression Multiply(IntExpression value) => Operator("*", value); + public IntExpression DivideBy(IntExpression value) => Operator("/", value); + + public static IntExpression operator +(IntExpression left, IntExpression right) => left.Add(right); + public static IntExpression operator -(IntExpression left, IntExpression right) => left.Minus(right); + public static IntExpression operator *(IntExpression left, IntExpression right) => left.Multiply(right); + public static IntExpression operator /(IntExpression left, IntExpression right) => left.DivideBy(right); + + private IntExpression Operator(string op, IntExpression other) => new(new BinaryOperatorExpression(op, this, other)); } } diff --git a/src/AutoRest.CSharp/Common/Output/Expressions/KnownValueExpressions/StringBuilderExpression.cs b/src/AutoRest.CSharp/Common/Output/Expressions/KnownValueExpressions/StringBuilderExpression.cs index 5fb476f3bf5..ea9e54f4026 100644 --- a/src/AutoRest.CSharp/Common/Output/Expressions/KnownValueExpressions/StringBuilderExpression.cs +++ b/src/AutoRest.CSharp/Common/Output/Expressions/KnownValueExpressions/StringBuilderExpression.cs @@ -10,7 +10,7 @@ namespace AutoRest.CSharp.Common.Output.Expressions.KnownValueExpressions { internal sealed record StringBuilderExpression(ValueExpression Untyped) : TypedValueExpression(Untyped) { - public StringExpression Length => new(Property(nameof(StringBuilder.Length))); + public IntExpression Length => new(Property(nameof(StringBuilder.Length))); public MethodBodyStatement Append(StringExpression value) => new InvokeInstanceMethodStatement(Untyped, nameof(StringBuilder.Append), value); @@ -27,5 +27,7 @@ internal sealed record StringBuilderExpression(ValueExpression Untyped) : TypedV public MethodBodyStatement Append(FormattableStringExpression value) => new InvokeInstanceMethodStatement(Untyped, nameof(StringBuilder.Append), value); public MethodBodyStatement AppendLine(FormattableStringExpression value) => new InvokeInstanceMethodStatement(Untyped, nameof(StringBuilder.AppendLine), value); + + public MethodBodyStatement Remove(ValueExpression startIndex, ValueExpression length) => new InvokeInstanceMethodStatement(Untyped, nameof(StringBuilder.Remove), startIndex, length); } } diff --git a/src/AutoRest.CSharp/Common/Output/Expressions/ValueExpressions/IndexerExpression.cs b/src/AutoRest.CSharp/Common/Output/Expressions/ValueExpressions/IndexerExpression.cs index 19d4c756b6a..965d3942036 100644 --- a/src/AutoRest.CSharp/Common/Output/Expressions/ValueExpressions/IndexerExpression.cs +++ b/src/AutoRest.CSharp/Common/Output/Expressions/ValueExpressions/IndexerExpression.cs @@ -1,7 +1,6 @@ // Copyright(c) Microsoft Corporation.All rights reserved. // Licensed under the MIT License. -using System; using AutoRest.CSharp.Generation.Writers; namespace AutoRest.CSharp.Common.Output.Expressions.ValueExpressions diff --git a/src/AutoRest.CSharp/Common/Output/Models/Types/HelperTypeProviders/System/ClientUriBuilderProvider.cs b/src/AutoRest.CSharp/Common/Output/Models/Types/HelperTypeProviders/System/ClientUriBuilderProvider.cs index acc3b458254..9e46a80f054 100644 --- a/src/AutoRest.CSharp/Common/Output/Models/Types/HelperTypeProviders/System/ClientUriBuilderProvider.cs +++ b/src/AutoRest.CSharp/Common/Output/Models/Types/HelperTypeProviders/System/ClientUriBuilderProvider.cs @@ -10,7 +10,6 @@ using AutoRest.CSharp.Common.Output.Expressions.ValueExpressions; using AutoRest.CSharp.Common.Output.Models; using AutoRest.CSharp.Generation.Types; -using AutoRest.CSharp.Output.Models.Serialization; using AutoRest.CSharp.Output.Models.Shared; using static AutoRest.CSharp.Common.Output.Models.Snippets; @@ -32,14 +31,12 @@ private ClientUriBuilderProvider() : base(Configuration.HelperNamespace, null) private readonly FieldDeclaration _uriBuilderField = new(FieldModifiers.Private, typeof(UriBuilder), "_uriBuilder"); private readonly FieldDeclaration _pathBuilderField = new(FieldModifiers.Private, typeof(StringBuilder), "_pathBuilder"); private readonly FieldDeclaration _queryBuilderField = new(FieldModifiers.Private, typeof(StringBuilder), "_queryBuilder"); - private readonly FieldDeclaration _pathSeparatorField = new(FieldModifiers.Private | FieldModifiers.Const, typeof(char), "PathSeparator", Literal('/'), SerializationFormat.Default); protected override IEnumerable BuildFields() { yield return _uriBuilderField; yield return _pathBuilderField; yield return _queryBuilderField; - yield return _pathSeparatorField; } private PropertyDeclaration? _uriBuilderProperty; @@ -156,9 +153,9 @@ private IEnumerable BuildAppendPathMethods() Assign(value, new InvokeStaticMethodExpression(typeof(Uri), nameof(Uri.EscapeDataString), new[]{ value })) }, EmptyLine, - new IfStatement(Equal(new IndexerExpression(value, Literal(0)), _pathSeparatorField)) + new IfStatement(And(And(GreaterThan(pathBuilder.Length, Int(0)), Equal(new IndexerExpression(pathBuilder, pathBuilder.Length - Int(1)), Literal('/'))), Equal(new IndexerExpression(value, Int(0)), Literal('/')))) { - Assign(value, value.Substring(Literal(1))) + pathBuilder.Remove(pathBuilder.Length - Int(1), Int(1)) }, EmptyLine, pathBuilder.Append(value), diff --git a/test/CadlRanchProjectsNonAzure/authentication/http/custom/src/Generated/Internal/ClientUriBuilder.cs b/test/CadlRanchProjectsNonAzure/authentication/http/custom/src/Generated/Internal/ClientUriBuilder.cs index df0eff3a7f0..f1aefb52089 100644 --- a/test/CadlRanchProjectsNonAzure/authentication/http/custom/src/Generated/Internal/ClientUriBuilder.cs +++ b/test/CadlRanchProjectsNonAzure/authentication/http/custom/src/Generated/Internal/ClientUriBuilder.cs @@ -14,7 +14,6 @@ internal class ClientUriBuilder private UriBuilder _uriBuilder; private StringBuilder _pathBuilder; private StringBuilder _queryBuilder; - private const char PathSeparator = '/'; public ClientUriBuilder() { @@ -42,9 +41,9 @@ public void AppendPath(string value, bool escape) value = Uri.EscapeDataString(value); } - if (value[0] == PathSeparator) + if (PathBuilder.Length > 0 && PathBuilder[PathBuilder.Length - 1] == '/' && value[0] == '/') { - value = value.Substring(1); + PathBuilder.Remove(PathBuilder.Length - 1, 1); } PathBuilder.Append(value); diff --git a/test/UnbrandedProjects.Tests/ClientUriBuilderTests.cs b/test/UnbrandedProjects.Tests/ClientUriBuilderTests.cs new file mode 100644 index 00000000000..87948b403c0 --- /dev/null +++ b/test/UnbrandedProjects.Tests/ClientUriBuilderTests.cs @@ -0,0 +1,461 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +using System; +using System.Collections.Generic; +using NUnit.Framework; +using UnbrandedTypeSpec; + +namespace UnbrandedProjects.Tests +{ + public class ClientUriBuilderTests + { + [TestCase("http://localhost", null, "http://localhost/")] + [TestCase("http://localhost/", null, "http://localhost/")] + [TestCase("http://localhost:12345", null, "http://localhost:12345/")] + [TestCase("http://localhost:12345/", null, "http://localhost:12345/")] + [TestCase("http://localhost/with", null, "http://localhost/with")] + [TestCase("http://localhost/with/", null, "http://localhost/with/")] + [TestCase("http://localhost:12345/with", null, "http://localhost:12345/with")] + [TestCase("http://localhost:12345/with/", null, "http://localhost:12345/with/")] + [TestCase("http://localhost", "path", "http://localhost/path")] + [TestCase("http://localhost/", "path", "http://localhost/path")] + [TestCase("http://localhost:12345", "path", "http://localhost:12345/path")] + [TestCase("http://localhost:12345/", "path", "http://localhost:12345/path")] + [TestCase("http://localhost/with", "path", "http://localhost/withpath")] + [TestCase("http://localhost/with/", "path", "http://localhost/with/path")] + [TestCase("http://localhost:12345/with", "path", "http://localhost:12345/withpath")] + [TestCase("http://localhost:12345/with/", "path", "http://localhost:12345/with/path")] + [TestCase("http://localhost", "/path", "http://localhost/path")] + [TestCase("http://localhost/", "/path", "http://localhost/path")] + [TestCase("http://localhost:12345", "/path", "http://localhost:12345/path")] + [TestCase("http://localhost:12345/", "/path", "http://localhost:12345/path")] + [TestCase("http://localhost/with", "/path", "http://localhost/with/path")] + [TestCase("http://localhost/with/", "/path", "http://localhost/with/path")] + [TestCase("http://localhost:12345/with", "/path", "http://localhost:12345/with/path")] + [TestCase("http://localhost:12345/with/", "/path", "http://localhost:12345/with/path")] + [TestCase("http://localhost", "/path/", "http://localhost/path/")] + [TestCase("http://localhost/", "/path/", "http://localhost/path/")] + [TestCase("http://localhost:12345", "/path/", "http://localhost:12345/path/")] + [TestCase("http://localhost:12345/", "/path/", "http://localhost:12345/path/")] + [TestCase("http://localhost/with", "/path/", "http://localhost/with/path/")] + [TestCase("http://localhost/with/", "/path/", "http://localhost/with/path/")] + [TestCase("http://localhost:12345/with", "/path/", "http://localhost:12345/with/path/")] + [TestCase("http://localhost:12345/with/", "/path/", "http://localhost:12345/with/path/")] + public void ResetThenAppendPath(string endpoint, string pathPart, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + if (pathPart != null) + { + builder.AppendPath(pathPart, false); + } + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", "one|1", "http://localhost/?one=1")] + [TestCase("http://localhost:12345", "one|1", "http://localhost:12345/?one=1")] + [TestCase("http://localhost/some", "one|1", "http://localhost/some?one=1")] + [TestCase("http://localhost:12345/some", "one|1", "http://localhost:12345/some?one=1")] + [TestCase("http://localhost/", "one|1", "http://localhost/?one=1")] + [TestCase("http://localhost:12345/", "one|1", "http://localhost:12345/?one=1")] + [TestCase("http://localhost/some/", "one|1", "http://localhost/some/?one=1")] + [TestCase("http://localhost:12345/some/", "one|1", "http://localhost:12345/some/?one=1")] + [TestCase("http://localhost", "one|1|two|2", "http://localhost/?one=1&two=2")] + [TestCase("http://localhost:12345", "one|1|two|2", "http://localhost:12345/?one=1&two=2")] + [TestCase("http://localhost/some", "one|1|two|2", "http://localhost/some?one=1&two=2")] + [TestCase("http://localhost:12345/some", "one|1|two|2", "http://localhost:12345/some?one=1&two=2")] + [TestCase("http://localhost/", "one|1|two|2", "http://localhost/?one=1&two=2")] + [TestCase("http://localhost:12345/", "one|1|two|2", "http://localhost:12345/?one=1&two=2")] + [TestCase("http://localhost/some/", "one|1|two|2", "http://localhost/some/?one=1&two=2")] + [TestCase("http://localhost:12345/some/", "one|1|two|2", "http://localhost:12345/some/?one=1&two=2")] + public void ResetThenAppendQuery(string endpoint, string queryPart, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + if (queryPart != null) + { + var parts = queryPart.Split('|'); + for (int i = 0; i < parts.Length; i += 2) + { + builder.AppendQuery(parts[i], parts[i + 1], false); + } + } + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", "some", "one|1", "http://localhost/some?one=1")] + [TestCase("http://localhost:12345", "some", "one|1", "http://localhost:12345/some?one=1")] + [TestCase("http://localhost/", "some/", "one|1", "http://localhost/some/?one=1")] + [TestCase("http://localhost:12345", "some/", "one|1", "http://localhost:12345/some/?one=1")] + [TestCase("http://localhost/", "/some", "one|1", "http://localhost/some?one=1")] + [TestCase("http://localhost:12345", "/some", "one|1", "http://localhost:12345/some?one=1")] + [TestCase("http://localhost/", "/some/", "one|1", "http://localhost/some/?one=1")] + [TestCase("http://localhost:12345", "/some/", "one|1", "http://localhost:12345/some/?one=1")] + [TestCase("http://localhost", "/some", "one|1|two|2", "http://localhost/some?one=1&two=2")] + [TestCase("http://localhost:12345", "/some", "one|1|two|2", "http://localhost:12345/some?one=1&two=2")] + [TestCase("http://localhost", "some/", "one|1|two|2", "http://localhost/some/?one=1&two=2")] + [TestCase("http://localhost:12345", "some/", "one|1|two|2", "http://localhost:12345/some/?one=1&two=2")] + [TestCase("http://localhost", "/some/", "one|1|two|2", "http://localhost/some/?one=1&two=2")] + [TestCase("http://localhost:12345", "/some/", "one|1|two|2", "http://localhost:12345/some/?one=1&two=2")] + public void ResetThenAppendPathThenAppendQuery(string endpoint, string pathPart, string queryPart, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + if (pathPart != null) + { + builder.AppendPath(pathPart, false); + } + + if (queryPart != null) + { + var parts = queryPart.Split('|'); + for (int i = 0; i < parts.Length; i += 2) + { + builder.AppendQuery(parts[i], parts[i + 1], false); + } + } + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", "some", "one|1", "http://localhost/some?one=1")] + [TestCase("http://localhost:12345", "some", "one|1", "http://localhost:12345/some?one=1")] + [TestCase("http://localhost/", "some/", "one|1", "http://localhost/some/?one=1")] + [TestCase("http://localhost:12345", "some/", "one|1", "http://localhost:12345/some/?one=1")] + [TestCase("http://localhost/", "/some", "one|1", "http://localhost/some?one=1")] + [TestCase("http://localhost:12345", "/some", "one|1", "http://localhost:12345/some?one=1")] + [TestCase("http://localhost/", "/some/", "one|1", "http://localhost/some/?one=1")] + [TestCase("http://localhost:12345", "/some/", "one|1", "http://localhost:12345/some/?one=1")] + [TestCase("http://localhost", "/some", "one|1|two|2", "http://localhost/some?one=1&two=2")] + [TestCase("http://localhost:12345", "/some", "one|1|two|2", "http://localhost:12345/some?one=1&two=2")] + [TestCase("http://localhost", "some/", "one|1|two|2", "http://localhost/some/?one=1&two=2")] + [TestCase("http://localhost:12345", "some/", "one|1|two|2", "http://localhost:12345/some/?one=1&two=2")] + [TestCase("http://localhost", "/some/", "one|1|two|2", "http://localhost/some/?one=1&two=2")] + [TestCase("http://localhost:12345", "/some/", "one|1|two|2", "http://localhost:12345/some/?one=1&two=2")] + public void ResetThenAppendQueryThenAppendPath(string endpoint, string pathPart, string queryPart, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + if (queryPart != null) + { + var parts = queryPart.Split('|'); + for (int i = 0; i < parts.Length; i += 2) + { + builder.AppendQuery(parts[i], parts[i + 1], false); + } + } + + if (pathPart != null) + { + builder.AppendPath(pathPart, false); + } + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", true, true, "http://localhost/true")] + [TestCase("http://localhost", true, false, "http://localhost/true")] + [TestCase("http://localhost", false, true, "http://localhost/false")] + [TestCase("http://localhost", false, false, "http://localhost/false")] + public void AppendPath_Bool(string endpoint, bool value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendPath(value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", 3.14f, true, "http://localhost/3.14")] + [TestCase("http://localhost", 3.14f, false, "http://localhost/3.14")] + [TestCase("http://localhost", -3.14f, true, "http://localhost/-3.14")] + [TestCase("http://localhost", -3.14f, false, "http://localhost/-3.14")] + public void AppendPath_Float(string endpoint, float value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendPath(value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", 3.14, true, "http://localhost/3.14")] + [TestCase("http://localhost", 3.14, false, "http://localhost/3.14")] + [TestCase("http://localhost", -3.14, true, "http://localhost/-3.14")] + [TestCase("http://localhost", -3.14, false, "http://localhost/-3.14")] + public void AppendPath_Double(string endpoint, double value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendPath(value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", 299792458, true, "http://localhost/299792458")] + [TestCase("http://localhost", 299792458, false, "http://localhost/299792458")] + [TestCase("http://localhost", -299792458, true, "http://localhost/-299792458")] + [TestCase("http://localhost", -299792458, false, "http://localhost/-299792458")] + public void AppendPath_Int(string endpoint, int value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendPath(value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", 299792458000000, true, "http://localhost/299792458000000")] + [TestCase("http://localhost", 299792458000000, false, "http://localhost/299792458000000")] + [TestCase("http://localhost", -299792458000000, true, "http://localhost/-299792458000000")] + [TestCase("http://localhost", -299792458000000, false, "http://localhost/-299792458000000")] + public void AppendPath_Long(string endpoint, long value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendPath(value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", new byte[] { 104, 101, 108, 108, 111 }, "U", true, "http://localhost/aGVsbG8")] + [TestCase("http://localhost", new byte[] { 104, 101, 108, 108, 111 }, "D", true, "http://localhost/aGVsbG8%3D")] + [TestCase("http://localhost", new byte[] { 104, 101, 108, 108, 111 }, "U", false, "http://localhost/aGVsbG8")] + [TestCase("http://localhost", new byte[] { 104, 101, 108, 108, 111 }, "D", false, "http://localhost/aGVsbG8=")] + public void AppendPath_ByteArray(string endpoint, byte[] value, string format, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendPath(value, format, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", new[] { "hello", "world" }, true, "http://localhost/hello%2Cworld")] + [TestCase("http://localhost", new[] { "hello", "world" }, false, "http://localhost/hello,world")] + public void AppendPath_StringArray(string endpoint, IEnumerable value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendPath(value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "D", true, "http://localhost/1905-06-30")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "U", true, "http://localhost/-2035622760")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "O", true, "http://localhost/1905-06-30T13%3A14%3A00.0000000Z")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "o", true, "http://localhost/1905-06-30T13%3A14%3A00.0000000Z")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "R", true, "http://localhost/Fri%2C 30 Jun 1905 13%3A14%3A00 GMT")] // TODO -- why spaces are not escaped? + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "D", false, "http://localhost/1905-06-30")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "U", false, "http://localhost/-2035622760")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "O", false, "http://localhost/1905-06-30T13:14:00.0000000Z")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "o", false, "http://localhost/1905-06-30T13:14:00.0000000Z")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "R", false, "http://localhost/Fri, 30 Jun 1905 13:14:00 GMT")] + public void AppendPath_DateTimeOffset(string endpoint, string value, string format, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + var dateTimeOffset = DateTimeOffset.Parse(value); + builder.AppendPath(dateTimeOffset, format, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", "02:15:00", "P", true, "http://localhost/PT2H15M")] + [TestCase("http://localhost", "02:15:00", "", true, "http://localhost/02%3A15%3A00")] + [TestCase("http://localhost", "02:15:00", null, true, "http://localhost/PT2H15M")] + [TestCase("http://localhost", "02:15:00", "P", false, "http://localhost/PT2H15M")] + [TestCase("http://localhost", "02:15:00", "", false, "http://localhost/02:15:00")] + [TestCase("http://localhost", "02:15:00", null, false, "http://localhost/PT2H15M")] + public void AppendPath_TimeSpan(string endpoint, string value, string format, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + var timeSpan = TimeSpan.Parse(value); + builder.AppendPath(timeSpan, format, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", "3f2504e0-4f89-11d3-9a0c-0305e82c3301", true, "http://localhost/3f2504e0-4f89-11d3-9a0c-0305e82c3301")] + [TestCase("http://localhost", "3f2504e0-4f89-11d3-9a0c-0305e82c3301", false, "http://localhost/3f2504e0-4f89-11d3-9a0c-0305e82c3301")] + public void AppendPath_Guid(string endpoint, string value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + var guid = Guid.Parse(value); + builder.AppendPath(guid, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", true, true, "http://localhost/?query=true")] + [TestCase("http://localhost", true, false, "http://localhost/?query=true")] + [TestCase("http://localhost", false, true, "http://localhost/?query=false")] + [TestCase("http://localhost", false, false, "http://localhost/?query=false")] + public void AppendQuery_Bool(string endpoint, bool value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendQuery("query", value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", 3.14f, true, "http://localhost/?query=3.14")] + [TestCase("http://localhost", 3.14f, false, "http://localhost/?query=3.14")] + [TestCase("http://localhost", -3.14f, true, "http://localhost/?query=-3.14")] + [TestCase("http://localhost", -3.14f, false, "http://localhost/?query=-3.14")] + public void AppendQuery_Float(string endpoint, float value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendQuery("query", value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", 3.14, true, "http://localhost/?query=3.14")] + [TestCase("http://localhost", 3.14, false, "http://localhost/?query=3.14")] + [TestCase("http://localhost", -3.14, true, "http://localhost/?query=-3.14")] + [TestCase("http://localhost", -3.14, false, "http://localhost/?query=-3.14")] + public void AppendQuery_Double(string endpoint, double value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendQuery("query", value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", 299792458, true, "http://localhost/?query=299792458")] + [TestCase("http://localhost", 299792458, false, "http://localhost/?query=299792458")] + [TestCase("http://localhost", -299792458, true, "http://localhost/?query=-299792458")] + [TestCase("http://localhost", -299792458, false, "http://localhost/?query=-299792458")] + public void AppendQuery_Int(string endpoint, int value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendQuery("query", value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", 299792458000000, true, "http://localhost/?query=299792458000000")] + [TestCase("http://localhost", 299792458000000, false, "http://localhost/?query=299792458000000")] + [TestCase("http://localhost", -299792458000000, true, "http://localhost/?query=-299792458000000")] + [TestCase("http://localhost", -299792458000000, false, "http://localhost/?query=-299792458000000")] + public void AppendQuery_Long(string endpoint, long value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendQuery("query", value, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", new byte[] { 104, 101, 108, 108, 111 }, "U", true, "http://localhost/?query=aGVsbG8")] + [TestCase("http://localhost", new byte[] { 104, 101, 108, 108, 111 }, "D", true, "http://localhost/?query=aGVsbG8%3D")] + [TestCase("http://localhost", new byte[] { 104, 101, 108, 108, 111 }, "U", false, "http://localhost/?query=aGVsbG8")] + [TestCase("http://localhost", new byte[] { 104, 101, 108, 108, 111 }, "D", false, "http://localhost/?query=aGVsbG8=")] + public void AppendQuery_ByteArray(string endpoint, byte[] value, string format, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendQuery("query", value, format, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "D", true, "http://localhost/?query=1905-06-30")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "U", true, "http://localhost/?query=-2035622760")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "O", true, "http://localhost/?query=1905-06-30T13%3A14%3A00.0000000Z")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "o", true, "http://localhost/?query=1905-06-30T13%3A14%3A00.0000000Z")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "R", true, "http://localhost/?query=Fri%2C 30 Jun 1905 13%3A14%3A00 GMT")] // TODO -- why spaces are not escaped? + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "D", false, "http://localhost/?query=1905-06-30")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "U", false, "http://localhost/?query=-2035622760")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "O", false, "http://localhost/?query=1905-06-30T13:14:00.0000000Z")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "o", false, "http://localhost/?query=1905-06-30T13:14:00.0000000Z")] + [TestCase("http://localhost", "6/30/1905 1:14:00 PM +00:00", "R", false, "http://localhost/?query=Fri, 30 Jun 1905 13:14:00 GMT")] + public void AppendQuery_DateTimeOffset(string endpoint, string value, string format, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + var dateTimeOffset = DateTimeOffset.Parse(value); + builder.AppendQuery("query", dateTimeOffset, format, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", "02:15:00", "P", true, "http://localhost/?query=PT2H15M")] + [TestCase("http://localhost", "02:15:00", "", true, "http://localhost/?query=02%3A15%3A00")] + [TestCase("http://localhost", "02:15:00", null, true, "http://localhost/?query=PT2H15M")] + [TestCase("http://localhost", "02:15:00", "P", false, "http://localhost/?query=PT2H15M")] + [TestCase("http://localhost", "02:15:00", "", false, "http://localhost/?query=02:15:00")] + [TestCase("http://localhost", "02:15:00", null, false, "http://localhost/?query=PT2H15M")] + public void AppendQuery_TimeSpan(string endpoint, string value, string format, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + var timeSpan = TimeSpan.Parse(value); + builder.AppendQuery("query", timeSpan, format, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", "3f2504e0-4f89-11d3-9a0c-0305e82c3301", true, "http://localhost/?query=3f2504e0-4f89-11d3-9a0c-0305e82c3301")] + [TestCase("http://localhost", "3f2504e0-4f89-11d3-9a0c-0305e82c3301", false, "http://localhost/?query=3f2504e0-4f89-11d3-9a0c-0305e82c3301")] + public void AppendQuery_Guid(string endpoint, string value, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + var guid = Guid.Parse(value); + builder.AppendQuery("query", guid, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + + [TestCase("http://localhost", new[] { "hello", "world" }, ",", true, "http://localhost/?query=hello%2Cworld")] + [TestCase("http://localhost", new[] { "hello", "world" }, ";", true, "http://localhost/?query=hello%3Bworld")] + [TestCase("http://localhost", new[] { "hello", "world" }, "|", true, "http://localhost/?query=hello|world")] + [TestCase("http://localhost", new[] { "hello", "world" }, ",", false, "http://localhost/?query=hello,world")] + [TestCase("http://localhost", new[] { "hello", "world" }, ";", false, "http://localhost/?query=hello;world")] + [TestCase("http://localhost", new[] { "hello", "world" }, "|", false, "http://localhost/?query=hello|world")] + public void AppendQueryDelimited(string endpoint, IEnumerable value, string delimiter, bool escape, string expected) + { + var builder = new ClientUriBuilder(); + builder.Reset(new Uri(endpoint)); + + builder.AppendQueryDelimited("query", value, delimiter, escape); + + Assert.AreEqual(expected, builder.ToUri().ToString()); + } + } +} diff --git a/test/UnbrandedProjects/Customized-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs b/test/UnbrandedProjects/Customized-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs index 13d01eec7fc..465e6b237e5 100644 --- a/test/UnbrandedProjects/Customized-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs +++ b/test/UnbrandedProjects/Customized-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs @@ -14,7 +14,6 @@ internal class ClientUriBuilder private UriBuilder _uriBuilder; private StringBuilder _pathBuilder; private StringBuilder _queryBuilder; - private const char PathSeparator = '/'; public ClientUriBuilder() { @@ -42,9 +41,9 @@ public void AppendPath(string value, bool escape) value = Uri.EscapeDataString(value); } - if (value[0] == PathSeparator) + if (PathBuilder.Length > 0 && PathBuilder[PathBuilder.Length - 1] == '/' && value[0] == '/') { - value = value.Substring(1); + PathBuilder.Remove(PathBuilder.Length - 1, 1); } PathBuilder.Append(value); diff --git a/test/UnbrandedProjects/NoTest-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs b/test/UnbrandedProjects/NoTest-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs index cf3544d4971..9975f9d0308 100644 --- a/test/UnbrandedProjects/NoTest-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs +++ b/test/UnbrandedProjects/NoTest-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs @@ -14,7 +14,6 @@ internal class ClientUriBuilder private UriBuilder _uriBuilder; private StringBuilder _pathBuilder; private StringBuilder _queryBuilder; - private const char PathSeparator = '/'; public ClientUriBuilder() { @@ -42,9 +41,9 @@ public void AppendPath(string value, bool escape) value = Uri.EscapeDataString(value); } - if (value[0] == PathSeparator) + if (PathBuilder.Length > 0 && PathBuilder[PathBuilder.Length - 1] == '/' && value[0] == '/') { - value = value.Substring(1); + PathBuilder.Remove(PathBuilder.Length - 1, 1); } PathBuilder.Append(value); diff --git a/test/UnbrandedProjects/Platform-OpenAI-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs b/test/UnbrandedProjects/Platform-OpenAI-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs index b24daf5251a..2f5fd8765f8 100644 --- a/test/UnbrandedProjects/Platform-OpenAI-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs +++ b/test/UnbrandedProjects/Platform-OpenAI-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs @@ -14,7 +14,6 @@ internal class ClientUriBuilder private UriBuilder _uriBuilder; private StringBuilder _pathBuilder; private StringBuilder _queryBuilder; - private const char PathSeparator = '/'; public ClientUriBuilder() { @@ -42,9 +41,9 @@ public void AppendPath(string value, bool escape) value = Uri.EscapeDataString(value); } - if (value[0] == PathSeparator) + if (PathBuilder.Length > 0 && PathBuilder[PathBuilder.Length - 1] == '/' && value[0] == '/') { - value = value.Substring(1); + PathBuilder.Remove(PathBuilder.Length - 1, 1); } PathBuilder.Append(value); diff --git a/test/UnbrandedProjects/Unbranded-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs b/test/UnbrandedProjects/Unbranded-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs index bcdf8d4f529..798b4d78cf0 100644 --- a/test/UnbrandedProjects/Unbranded-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs +++ b/test/UnbrandedProjects/Unbranded-TypeSpec/src/Generated/Internal/ClientUriBuilder.cs @@ -14,7 +14,6 @@ internal class ClientUriBuilder private UriBuilder _uriBuilder; private StringBuilder _pathBuilder; private StringBuilder _queryBuilder; - private const char PathSeparator = '/'; public ClientUriBuilder() { @@ -42,9 +41,9 @@ public void AppendPath(string value, bool escape) value = Uri.EscapeDataString(value); } - if (value[0] == PathSeparator) + if (PathBuilder.Length > 0 && PathBuilder[PathBuilder.Length - 1] == '/' && value[0] == '/') { - value = value.Substring(1); + PathBuilder.Remove(PathBuilder.Length - 1, 1); } PathBuilder.Append(value);