Skip to content

Commit

Permalink
Add CompositeFormat.MinimumArgumentCount and remove TryParse (#85348)
Browse files Browse the repository at this point in the history
* Add CompositeFormat.MinimumArgumentCount

* Remove CompositeFormat.TryParse

It encourages bad patterns of consumption.
  • Loading branch information
stephentoub authored Apr 26, 2023
1 parent 1dd5a8c commit 6007637
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -85,31 +85,13 @@ public static CompositeFormat Parse([StringSyntax(StringSyntaxAttribute.Composit
return new CompositeFormat(format, segments.ToArray());
}

/// <summary>Try to parse the composite format string <paramref name="format"/>.</summary>
/// <param name="format">The string to parse.</param>
/// <param name="compositeFormat">The parsed <see cref="CompositeFormat"/> if parsing was successful; otherwise, null.</param>
/// <returns><see langword="true"/> the <paramref name="format"/> can be parsed successfully; otherwise, <see langword="false"/>.</returns>
public static bool TryParse([StringSyntax(StringSyntaxAttribute.CompositeFormat)] string? format, [NotNullWhen(true)] out CompositeFormat? compositeFormat)
{
if (format is not null)
{
var segments = new List<(string? Literal, int ArgIndex, int Alignment, string? Format)>();
int failureOffset = default;
ExceptionResource failureReason = default;
if (TryParseLiterals(format, segments, ref failureOffset, ref failureReason))
{
compositeFormat = new CompositeFormat(format, segments.ToArray());
return true;
}
}

compositeFormat = null;
return false;
}

/// <summary>Gets the original composite format string used to create this <see cref="CompositeFormat"/> instance.</summary>
public string Format { get; }

/// <summary>Gets the minimum number of arguments that must be passed to a formatting operation using this <see cref="CompositeFormat"/>.</summary>
/// <remarks>It's permissible to supply more arguments than this value, but it's an error to pass fewer.</remarks>
public int MinimumArgumentCount => _argsRequired;

/// <summary>Throws an exception if the specified number of arguments is fewer than the number required.</summary>
/// <param name="numArgs">The number of arguments provided by the caller.</param>
/// <exception cref="FormatException">An insufficient number of arguments were provided.</exception>
Expand Down
2 changes: 1 addition & 1 deletion src/libraries/System.Runtime/ref/System.Runtime.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14194,8 +14194,8 @@ public sealed class CompositeFormat
{
internal CompositeFormat() { }
public static System.Text.CompositeFormat Parse([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format) { throw null; }
public static bool TryParse([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute("CompositeFormat")] string format, [System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] out System.Text.CompositeFormat? compositeFormat) { throw null; }
public string Format { get { throw null; } }
public int MinimumArgumentCount { get { throw null; } }
}
public abstract partial class Decoder
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Linq;
using Xunit;

namespace System.Text.Tests
Expand All @@ -13,9 +14,6 @@ public void NullArgument_Throws()
{
AssertExtensions.Throws<ArgumentNullException>("format", () => CompositeFormat.Parse(null));

Assert.False(CompositeFormat.TryParse(null, out CompositeFormat? compositeFormat));
Assert.Null(compositeFormat);

AssertExtensions.Throws<ArgumentNullException>("format", () => string.Format(null, (CompositeFormat)null, 0));
AssertExtensions.Throws<ArgumentNullException>("format", () => string.Format(null, (CompositeFormat)null, 0, 0));
AssertExtensions.Throws<ArgumentNullException>("format", () => string.Format(null, (CompositeFormat)null, 0, 0, 0));
Expand Down Expand Up @@ -55,6 +53,30 @@ public static void DebuggerDisplay_ShowsFormat()
Assert.Equal($"\"{format}\"", DebuggerAttributes.ValidateDebuggerDisplayReferences(cf));
}

[Theory]
[InlineData("", 0)]
[InlineData("testing 123", 0)]
[InlineData("testing {{123}}", 0)]
[InlineData("{0}", 1)]
[InlineData("{0} {1}", 2)]
[InlineData("{2}", 3)]
[InlineData("{2} {0}", 3)]
[InlineData("{1} {34} {3}", 35)]
public static void MinimumArgumentCount_MatchesExpectedValue(string format, int expected)
{
CompositeFormat cf = CompositeFormat.Parse(format);

Assert.Equal(expected, cf.MinimumArgumentCount);

string s = string.Format(null, cf, Enumerable.Repeat((object)"arg", expected).ToArray());
Assert.NotNull(s);

if (expected != 0)
{
Assert.Throws<FormatException>(() => string.Format(null, cf, Enumerable.Repeat((object)"arg", expected - 1).ToArray()));
}
}

[Theory]
[MemberData(nameof(System.Tests.StringTests.Format_Valid_TestData), MemberType = typeof(System.Tests.StringTests))]
public static void StringFormat_Valid(IFormatProvider provider, string format, object[] values, string expected)
Expand All @@ -63,10 +85,6 @@ public static void StringFormat_Valid(IFormatProvider provider, string format, o
Assert.NotNull(cf);
Assert.Same(format, cf.Format);

Assert.True(CompositeFormat.TryParse(format, out CompositeFormat? cf2));
Assert.NotNull(cf2);
Assert.Same(format, cf2.Format);

Assert.Equal(expected, string.Format(provider, cf, values));

Assert.Equal(expected, string.Format(provider, cf, (ReadOnlySpan<object?>)values));
Expand Down Expand Up @@ -95,10 +113,6 @@ public static void StringBuilderAppendFormat_Valid(IFormatProvider provider, str
Assert.NotNull(cf);
Assert.Same(format, cf.Format);

Assert.True(CompositeFormat.TryParse(format, out CompositeFormat? cf2));
Assert.NotNull(cf2);
Assert.Same(format, cf2.Format);

var sb = new StringBuilder();

Assert.Same(sb, sb.AppendFormat(provider, cf, values));
Expand Down Expand Up @@ -135,10 +149,6 @@ public static void MemoryExtensionsTryWrite_Valid(IFormatProvider provider, stri
Assert.NotNull(cf);
Assert.Same(format, cf.Format);

Assert.True(CompositeFormat.TryParse(format, out CompositeFormat? cf2));
Assert.NotNull(cf2);
Assert.Same(format, cf2.Format);

char[] dest = new char[expected.Length];
int charsWritten;

Expand Down Expand Up @@ -189,9 +199,6 @@ public static void Parse_Invalid_FormatExceptionFromFormat(IFormatProvider provi
_ = args;

Assert.Throws<FormatException>(() => CompositeFormat.Parse(format));

Assert.False(CompositeFormat.TryParse(format, out CompositeFormat? compositeFormat));
Assert.Null(compositeFormat);
}

[Theory]
Expand Down

0 comments on commit 6007637

Please sign in to comment.