Skip to content

Commit

Permalink
feat: implement IParsable<T> on Iban type (#138)
Browse files Browse the repository at this point in the history
  • Loading branch information
skwasjer authored Jun 9, 2023
1 parent 7308a34 commit 380c4fe
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 0 deletions.
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);
}
}

}

0 comments on commit 380c4fe

Please sign in to comment.