diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ArgumentDefinition.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ArgumentDefinition.cs index 7dda538078d..6c7e62bd102 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ArgumentDefinition.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/src/Providers/ArgumentDefinition.cs @@ -11,6 +11,7 @@ using Microsoft.TypeSpec.Generator.Statements; using static Microsoft.TypeSpec.Generator.Snippets.ArgumentSnippets; using static Microsoft.TypeSpec.Generator.Snippets.Snippet; +using static Microsoft.TypeSpec.Generator.Snippets.StringSnippets; namespace Microsoft.TypeSpec.Generator.Providers { @@ -20,6 +21,9 @@ private class Template { } private const string AssertNotNullMethodName = "AssertNotNull"; private const string AssertNotNullOrEmptyMethodName = "AssertNotNullOrEmpty"; + private const string AssertNotNullOrWhiteSpaceMethodName = "AssertNotNullOrWhiteSpace"; + private const string AssertInRangeMethodName = "AssertInRange"; + private const string CheckNotNullOrEmptyMethodName = "CheckNotNullOrEmpty"; private readonly CSharpType _t = typeof(Template<>).GetGenericArguments()[0]; private readonly ParameterProvider _nameParam = new ParameterProvider("name", $"The name.", typeof(string)); @@ -65,9 +69,60 @@ protected internal override MethodProvider[] BuildMethods() BuildAssertNotNullStruct(), BuildAssertNotNullOrEmptyCollection(), BuildAssertNotNullOrEmptyString(), + BuildAssertNotNullOrWhiteSpace(), + BuildAssertInRange(), + BuildCheckNotNullOrEmpty(), ]; } + private MethodProvider BuildAssertNotNullOrWhiteSpace() + { + var valueParam = new ParameterProvider("value", $"The value.", typeof(string)); + var signature = GetSignature(AssertNotNullOrWhiteSpaceMethodName, [valueParam, _nameParam]); + return new MethodProvider(signature, new MethodBodyStatement[] + { + AssertNotNullSnippet(valueParam), + new IfStatement(IsNullOrWhiteSpace(valueParam.As())) + { + ThrowArgumentException("Value cannot be empty or contain only white-space characters.") + } + }, + this); + } + + private MethodProvider BuildAssertInRange() + { + var valueParam = new ParameterProvider("value", $"The value.", _t); + var minimumParam = new ParameterProvider("minimum", $"The minimum value.", _t); + var maximumParam = new ParameterProvider("maximum", $"The maximum value.", _t); + var whereExpression = Where.NotNull(_t).And(new CSharpType(typeof(IComparable<>), _t)); + var signature = GetSignature(AssertInRangeMethodName, [valueParam, minimumParam, maximumParam, _nameParam], [_t], [whereExpression]); + return new MethodProvider(signature, new MethodBodyStatement[] + { + new IfStatement(minimumParam.Invoke("CompareTo", valueParam).GreaterThan(Literal(0))) + { + Throw(New.ArgumentOutOfRangeException(_nameParam, "Value is less than the minimum allowed.", false)) + }, + new IfStatement(maximumParam.Invoke("CompareTo", valueParam).LessThan(Literal(0))) + { + Throw(New.ArgumentOutOfRangeException(_nameParam, "Value is greater than the maximum allowed.", false)) + } + }, + this); + } + + private MethodProvider BuildCheckNotNullOrEmpty() + { + var valueParam = new ParameterProvider("value", $"The value.", typeof(string)); + var signature = GetSignature(CheckNotNullOrEmptyMethodName, [valueParam, _nameParam], returnType: typeof(string)); + return new MethodProvider(signature, new MethodBodyStatement[] + { + Static().Invoke(AssertNotNullOrEmptyMethodName, [valueParam, _nameParam]).Terminate(), + Return(valueParam) + }, + this); + } + private MethodProvider BuildAssertNotNullOrEmptyString() { var valueParam = new ParameterProvider("value", $"The value.", typeof(string)); diff --git a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ArgumentTests.cs b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ArgumentTests.cs index 05055d25ba1..222522530a6 100644 --- a/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ArgumentTests.cs +++ b/packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator/test/Providers/ArgumentTests.cs @@ -59,6 +59,71 @@ public void NotNullOrEmptyStringThrowsOnEmpty() Assert.Throws(() => Argument.AssertNotNullOrEmpty(string.Empty, "value")); } + [Test] + public void NotNullOrWhiteSpace() + { + string value = "test"; + Argument.AssertNotNullOrWhiteSpace(value, "value"); + } + + [Test] + public void NotNullOrWhiteSpaceThrowsOnNull() + { + string? value = null; + Assert.Throws(() => Argument.AssertNotNullOrWhiteSpace(value, "value")); + } + + [Test] + public void NotNullOrWhiteSpaceThrowsOnWhiteSpace() + { + Assert.Throws(() => Argument.AssertNotNullOrWhiteSpace(" ", "value")); + } + + [Test] + public void NotNullOrWhiteSpaceThrowsOnEmpty() + { + Assert.Throws(() => Argument.AssertNotNullOrWhiteSpace(string.Empty, "value")); + } + + [Test] + public void AssertInRange() + { + Argument.AssertInRange(5, 1, 10, "value"); + } + + [Test] + public void AssertInRangeThrowsWhenBelowMinimum() + { + Assert.Throws(() => Argument.AssertInRange(0, 1, 10, "value")); + } + + [Test] + public void AssertInRangeThrowsWhenAboveMaximum() + { + Assert.Throws(() => Argument.AssertInRange(11, 1, 10, "value")); + } + + [Test] + public void CheckNotNullOrEmpty() + { + string value = "test"; + string result = Argument.CheckNotNullOrEmpty(value, "value"); + Assert.AreEqual("test", result); + } + + [Test] + public void CheckNotNullOrEmptyThrowsOnNull() + { + string? value = null; + Assert.Throws(() => Argument.CheckNotNullOrEmpty(value, "value")); + } + + [Test] + public void CheckNotNullOrEmptyThrowsOnEmpty() + { + Assert.Throws(() => Argument.CheckNotNullOrEmpty(string.Empty, "value")); + } + private readonly struct TestStructure : IEquatable { internal readonly string A; diff --git a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/Argument.cs b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/Argument.cs index ec840fc17ad..e9d84f503cd 100644 --- a/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/Argument.cs +++ b/packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Internal/Argument.cs @@ -70,5 +70,44 @@ public static void AssertNotNullOrEmpty(string value, string name) throw new ArgumentException("Value cannot be an empty string.", name); } } + + /// The value. + /// The name. + public static void AssertNotNullOrWhiteSpace(string value, string name) + { + if (value is null) + { + throw new ArgumentNullException(name); + } + if (string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentException("Value cannot be empty or contain only white-space characters.", name); + } + } + + /// The value. + /// The minimum value. + /// The maximum value. + /// The name. + public static void AssertInRange(T value, T minimum, T maximum, string name) + where T : notnull, IComparable + { + if (minimum.CompareTo(value) > 0) + { + throw new ArgumentOutOfRangeException(name, "Value is less than the minimum allowed."); + } + if (maximum.CompareTo(value) < 0) + { + throw new ArgumentOutOfRangeException(name, "Value is greater than the maximum allowed."); + } + } + + /// The value. + /// The name. + public static string CheckNotNullOrEmpty(string value, string name) + { + AssertNotNullOrEmpty(value, name); + return value; + } } }