Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: implement IParsable<T> on Iban type #138

Merged
merged 1 commit into from
Jun 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 51 additions & 0 deletions src/IbanNet/Iban.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ namespace IbanNet;
#endif
public sealed class Iban
: IEquatable<Iban>,
#if NET7_0_OR_GREATER
IParsable<Iban>,
#endif
IFormattable
{
/// <summary>
Expand Down Expand Up @@ -275,4 +278,52 @@ public override int GetHashCode()
: _iban.Substring(structure.Position, structure.Length);
#endif
}

/// <summary>
/// Converts the specified <paramref name="s" /> into an <see cref="Iban" />.
/// </summary>
/// <param name="s">The IBAN value to parse.</param>
/// <returns>An <see cref="Iban" /> if the <paramref name="s" /> is converted successfully.</returns>
/// <exception cref="ArgumentNullException">Thrown when the specified <paramref name="s" /> is <see langword="null" />.</exception>
/// <exception cref="IbanFormatException">Thrown when the specified <paramref name="s" /> is not a valid IBAN.</exception>
public static Iban Parse(string s) => Parse(s, null);

/// <summary>
/// Converts the specified <paramref name="s" /> into an <see cref="Iban" />.
/// </summary>
/// <param name="s">The IBAN value to parse.</param>
/// <param name="provider">An object that supplies culture-specific formatting information about <paramref name="s" />.</param>
/// <returns>An <see cref="Iban" /> if the <paramref name="s" /> is converted successfully.</returns>
/// <exception cref="ArgumentNullException">Thrown when the specified <paramref name="s" /> is <see langword="null" />.</exception>
/// <exception cref="IbanFormatException">Thrown when the specified <paramref name="s" /> is not a valid IBAN.</exception>
#pragma warning disable IDE0060
public static Iban Parse(string s, IFormatProvider? provider)
#pragma warning restore IDE0060
{
var parser = new IbanParser(IbanRegistry.Default);
return parser.Parse(s);
}

/// <summary>
/// Tries to convert the specified <paramref name="s" /> into an <see cref="Iban" />.
/// </summary>
/// <param name="s">The IBAN value to parse.</param>
/// <param name="result">The <see cref="Iban" /> if the <paramref name="s" /> is converted successfully.</param>
/// <returns><see langword="true" /> if the <paramref name="s" /> is converted successfully, or <see langword="false" /> otherwise</returns>
public static bool TryParse(string? s, [NotNullWhen(true)] out Iban? result) => TryParse(s, null, out result);

/// <summary>
/// Tries to convert the specified <paramref name="s" /> into an <see cref="Iban" />.
/// </summary>
/// <param name="s">The IBAN value to parse.</param>
/// <param name="provider">An object that supplies culture-specific formatting information about <paramref name="s" />.</param>
/// <param name="result">The <see cref="Iban" /> if the <paramref name="s" /> is converted successfully.</param>
/// <returns><see langword="true" /> if the <paramref name="s" /> is converted successfully, or <see langword="false" /> otherwise</returns>
#pragma warning disable IDE0060
public static bool TryParse(string? s, IFormatProvider? provider, [NotNullWhen(true)] out Iban? result)
#pragma warning restore IDE0060
{
var parser = new IbanParser(IbanRegistry.Default);
return parser.TryParse(s, out result);
}
}
110 changes: 110 additions & 0 deletions test/IbanNet.Tests/IbanTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using IbanNet.Registry;
using IbanNet.Registry.Swift;
using IbanNet.Validation.Results;
using TestHelpers;

namespace IbanNet;
Expand Down Expand Up @@ -375,4 +376,113 @@ public void Given_that_json_iban_is_invalid_when_deserializing_it_should_throw()
}
}
#endif

public sealed class When_parsing_iban : IbanTests
{
[Fact]
public void With_null_value_should_throw()
{
string? value = null;

// Act
Action act = () => Iban.Parse(value!);

// Assert
act.Should()
.Throw<ArgumentNullException>("the provided value was null")
.WithParameterName(nameof(value));
}

[Fact]
public void With_invalid_value_should_throw()
{
// Act
Action act = () => Iban.Parse(TestValues.InvalidIban);

// Assert
IbanFormatException ex = act.Should().Throw<IbanFormatException>("the provided value was invalid").Which;
ex.Result.Should().BeEquivalentTo(new ValidationResult
{
Error = new IllegalCountryCodeCharactersResult(0),
AttemptedValue = TestValues.InvalidIban
});
ex.InnerException.Should().BeNull();
}

[Theory]
[InlineData("NL91 ABNA 0417 1643 00")]
[InlineData("NL91\tABNA\t0417\t1643\t00")]
[InlineData(" NL91 ABNA041 716 4300 ")]
[InlineData("nl91 ABNA041716\t4300")]
public void Given_that_iban_contains_whitespace_or_lowercase_when_parsing_it_should_succeed(string iban)
{
const string expectedNormalizedIban = "NL91ABNA0417164300";

// Act
var actual = Iban.Parse(iban);

// Assert
actual.ToString().Should().Be(expectedNormalizedIban);
}

[Fact]
public void With_valid_value_should_return_iban()
{
Iban? iban = null;

// Act
Action act = () => iban = Iban.Parse(TestValues.ValidIban);

// Assert
act.Should().NotThrow<IbanFormatException>();
iban.Should()
.NotBeNull("the value should be parsed")
.And.BeOfType<Iban>()
.Which.ToString()
.Should()
.Be(TestValues.ValidIban, "the returned value should match the provided value");
}
}

public sealed class When_trying_to_parse_iban : IbanTests
{
[Fact]
public void With_null_value_should_return_false()
{
// Act
bool actual = Iban.TryParse(null, out Iban? iban);

// Assert
actual.Should().BeFalse("the provided value was null which is not valid");
iban.Should().BeNull("parsing did not succeed");
}

[Fact]
public void With_invalid_value_should_return_false()
{
// Act
bool actual = Iban.TryParse(TestValues.InvalidIban, out Iban? iban);

// Assert
actual.Should().BeFalse("the provided value was invalid");
iban.Should().BeNull("parsing did not succeed");
}

[Fact]
public void With_valid_value_should_pass()
{
// Act
bool actual = Iban.TryParse(TestValues.ValidIban, out Iban? iban);

// Assert
actual.Should().BeTrue("the provided value was valid");
iban.Should()
.NotBeNull()
.And.BeOfType<Iban>()
.Which.ToString()
.Should()
.Be(TestValues.ValidIban);
}
}

}