Skip to content

Commit

Permalink
implement IParseable<MimeType> and ISpanParseable<MimeType>
Browse files Browse the repository at this point in the history
  • Loading branch information
smdn committed Apr 23, 2022
1 parent cafe5bf commit 987ff2f
Show file tree
Hide file tree
Showing 5 changed files with 197 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ SPDX-License-Identifier: MIT
<PackageTags>MIME;MIME-type</PackageTags>
</PropertyGroup>

<!-- enable feature 'generic math' -->
<Import Project="..\FeatureGenericMath.props" />

<ItemGroup>
<ProjectReference VersionRange="[3.0.0,4.0.0)" Include="..\Smdn.Fundamental.Exception\Smdn.Fundamental.Exception.csproj" />
<PackageReference Include="System.Memory" />
Expand Down
77 changes: 68 additions & 9 deletions src/Smdn.Fundamental.MimeType/Smdn/MimeType.IParseable.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ partial class MimeType
#pragma warning restore IDE0040
#if FEATURE_GENERIC_MATH
:
#if !OBSOLETE_MEMBER
IParseable<MimeType>,
#endif
ISpanParseable<MimeType>
#endif
{
Expand All @@ -43,14 +40,57 @@ public static bool TryParse(
[NotNullWhen(true)]
#endif
out MimeType? result
)
=> TryParse(s, provider: null, out result);

// IParseable<TSelf>.TryParse
public static bool TryParse(
string? s,
IFormatProvider? provider,
#if NULL_STATE_STATIC_ANALYSIS_ATTRIBUTES
[NotNullWhen(true)]
#endif
out MimeType result
)
{
result = null;
result = null!;

if (s is null)
return false;
if (!TryParse(s.AsSpan(), nameof(s), onParseError: OnParseError.ReturnFalse, out var ret))

if (
!TryParse(
s.AsSpan(),
nameof(s),
onParseError: OnParseError.ReturnFalse,
provider: provider,
out var ret
)
) {
return false;
}

result = new(ret);

return true;
}

// ISpanParseable<TSelf>.TryParse
public static bool TryParse(ReadOnlySpan<char> s, IFormatProvider? provider, out MimeType result)
{
result = null!;

if (
!TryParse(
s,
nameof(s),
onParseError: OnParseError.ReturnFalse,
provider: provider,
out var ret
)
) {
return false;
}

result = new(ret);

Expand All @@ -63,19 +103,35 @@ out MimeType? result
public static (string type, string subType) Parse(string s)
=> MimeTypeStringExtensions.Split(s);
#pragma warning restore SA1316
#else
public static MimeType Parse(string s)
#endif

// IParseable<TSelf>.Parse
public static MimeType Parse(string s, IFormatProvider? provider = null)
{
TryParse(
s: (s ?? throw new ArgumentNullException(nameof(s))).AsSpan(),
paramName: nameof(s),
throwIfInvalid: OnParseError.ThrowFormatException,
onParseError: OnParseError.ThrowFormatException,
provider: provider,
out var result
);

return new(result.Type, result.SubType);
}

// ISpanParseable<TSelf>.Parse
public static MimeType Parse(ReadOnlySpan<char> s, IFormatProvider? provider = null)
{
TryParse(
s: s,
paramName: nameof(s),
onParseError: OnParseError.ThrowFormatException,
provider: provider,
out var result
);

return new(result.Type, result.SubType);
}
#endif

internal enum OnParseError {
ThrowFormatException,
Expand All @@ -87,6 +143,9 @@ internal static bool TryParse(
ReadOnlySpan<char> s,
string paramName,
OnParseError onParseError,
#pragma warning disable IDE0060
IFormatProvider? provider,
#pragma warning restore IDE0060
out (string Type, string SubType) result
)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ public static bool TrySplit(
s: mimeType.AsSpan(),
paramName: nameof(mimeType),
onParseError: MimeType.OnParseError.ReturnFalse,
provider: null,
out result
);
}
Expand All @@ -40,6 +41,7 @@ string paramName
s: mimeType.AsSpan(),
paramName: paramName,
onParseError: MimeType.OnParseError.ThrowArgumentException,
provider: null,
out var result
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,7 @@ SPDX-License-Identifier: MIT
<ItemGroup>
<PackageReference Include="Smdn.Test.NUnit.Utils" />
</ItemGroup>

<!-- enable feature 'generic math' -->
<Import Project="..\..\src\FeatureGenericMath.props" />
</Project>
130 changes: 121 additions & 9 deletions tests/Smdn.Fundamental.MimeType/Smdn/MimeType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -239,26 +239,138 @@ private static System.Collections.IEnumerable YieldParseInvalidFormatTestCases()
yield return new object[] { "text/plain/foo", typeof(FormatException) };
}

#if false
[TestCaseSource(nameof(YieldParseValidTestCases))]
public void TestParse(string s, MimeType expected)
=> Assert.AreEqual((expected.Type, expected.SubType), MimeType.Parse(s));
#endif
=> Assert.AreEqual(expected, MimeType.Parse(s, provider: null));

[TestCaseSource(nameof(YieldParseValidTestCases))]
public void TestParse_ReadOnlySpanOfChar(string s, MimeType expected)
=> Assert.AreEqual(expected, MimeType.Parse(s.AsSpan(), provider: null));

[TestCaseSource(nameof(YieldParseValidTestCases))]
public void TestTryParse(string s, MimeType expected)
{
Assert.IsTrue(MimeType.TryParse(s, out MimeType result));
Assert.IsTrue(MimeType.TryParse(s, provider: null, out var result));
Assert.AreEqual(expected, result);
}

#if false
[TestCaseSource(nameof(YieldParseValidTestCases))]
public void TestTryParse_ReadOnlySpanOfChar(string s, MimeType expected)
{
Assert.IsTrue(MimeType.TryParse(s.AsSpan(), provider: null, out var result));
Assert.AreEqual(expected, result);
}

#if FEATURE_GENERIC_MATH
[TestCaseSource(nameof(YieldParseValidTestCases))]
public void IParseable_Parse(string s, MimeType expected)
{
Assert.AreEqual(expected, Parse<MimeType>(s));

static TSelf Parse<TSelf>(string s) where TSelf : IParseable<TSelf>
=> TSelf.Parse(s, provider: null);
}

[TestCaseSource(nameof(YieldParseValidTestCases))]
public void ISpanParseable_Parse(string s, MimeType expected)
{
Assert.AreEqual(expected, Parse<MimeType>(s.AsSpan()));

static TSelf Parse<TSelf>(ReadOnlySpan<char> s) where TSelf : ISpanParseable<TSelf>
=> TSelf.Parse(s, provider: null);
}

[TestCaseSource(nameof(YieldParseValidTestCases))]
public void IParseable_TryParse(string s, MimeType expected)
{
Assert.IsTrue(TryParse<MimeType>(s, out var result));
Assert.AreEqual(expected, result);

static bool TryParse<TSelf>(string s, out TSelf result) where TSelf : IParseable<TSelf>
=> TSelf.TryParse(s, provider: null, out result);
}

[TestCaseSource(nameof(YieldParseValidTestCases))]
public void ISpanParseable_TryParse(string s, MimeType expected)
{
Assert.IsTrue(TryParse<MimeType>(s.AsSpan(), out var result));
Assert.AreEqual(expected, result);

static bool TryParse<TSelf>(ReadOnlySpan<char> s, out TSelf result) where TSelf : ISpanParseable<TSelf>
=> TSelf.TryParse(s, provider: null, out result);
}
#endif

[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
public void TestParse_InvalidFormat(string s, Type expectedExceptionType)
=> Assert.Throws(expectedExceptionType, () => MimeType.Parse(s));
#endif
=> Assert.Throws(expectedExceptionType, () => MimeType.Parse(s, provider: null));

[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
public void TestParse_ReadOnlySpanOfChar_InvalidFormat(string s, Type expectedExceptionType)
{
if (s is null)
Assert.Pass();

Assert.Throws(expectedExceptionType, () => MimeType.Parse(s.AsSpan(), provider: null));
}

[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
public void TestTryParse_InvalidFormat(string s, Type _)
=> Assert.IsFalse(MimeType.TryParse(s, out MimeType _));
public void TestTryParse_InvalidFormat(string s, Type discard)
=> Assert.IsFalse(MimeType.TryParse(s, provider: null, out _));

[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
public void TestTryParse_ReadOnlySpanOfChar_InvalidFormat(string s, Type discard)
{
if (s is null)
Assert.Pass();

Assert.IsFalse(MimeType.TryParse(s.AsSpan(), provider: null, out _));
}

#if FEATURE_GENERIC_MATH
[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
public void IParseable_Parse_InvalidFormat(string s, Type expectedExceptionType)
{
Assert.Throws(expectedExceptionType, () => Parse<MimeType>(s));

static TSelf Parse<TSelf>(string s) where TSelf : IParseable<TSelf>
=> TSelf.Parse(s, provider: null);
}

[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
public void ISpanParseable_Parse_InvalidFormat(string s, Type expectedExceptionType)
{
if (s is null)
Assert.Pass();

Assert.Throws(expectedExceptionType, () => Parse<MimeType>(s.AsSpan()));

static TSelf Parse<TSelf>(ReadOnlySpan<char> s) where TSelf : ISpanParseable<TSelf>
=> TSelf.Parse(s, provider: null);
}

[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
public void IParseable_TryParse_InvalidFormat(string s, Type discard)
{
if (s is null)
Assert.Pass();

Assert.IsFalse(TryParse<MimeType>(s, out _));

static bool TryParse<TSelf>(string s, out TSelf result) where TSelf : IParseable<TSelf>
=> TSelf.TryParse(s, provider: null, out result);
}

[TestCaseSource(nameof(YieldParseInvalidFormatTestCases))]
public void ISpanParseable_TryParse_InvalidFormat(string s, Type discard)
{
if (s is null)
Assert.Pass();

Assert.IsFalse(TryParse<MimeType>(s.AsSpan(), out _));

static bool TryParse<TSelf>(ReadOnlySpan<char> s, out TSelf result) where TSelf : ISpanParseable<TSelf>
=> TSelf.TryParse(s, provider: null, out result);
}
#endif
}

0 comments on commit 987ff2f

Please sign in to comment.