Skip to content

Commit 4783cc7

Browse files
authored
Fix: Make BIC optional for Girocode Version 2 (#622)
* Fix: Make BIC optional for Girocode Version 2 - Modified IsValidBic to accept a 'required' parameter - BIC is now required for Version 1 (as per spec) - BIC is optional for Version 2 (as per spec) - Fixed NullReferenceException when BIC is null - Added comprehensive tests for all scenarios: - Version 2 with null BIC (passes) - Version 2 with empty BIC (passes) - Version 2 with valid BIC (passes) - Version 2 with invalid BIC (throws exception) - Version 1 with null BIC (throws exception) - Version 1 with empty BIC (throws exception) Fixes issue where Girocode constructor threw NullReferenceException when BIC was null with Version 2, which should be allowed per the Girocode specification. * update * update api tests
1 parent aeaf5e5 commit 4783cc7

File tree

7 files changed

+153
-7
lines changed

7 files changed

+153
-7
lines changed

QRCoder/PayloadGenerator.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,18 @@ private static bool IsValidQRIban(string iban)
6565
private static bool IsValidBic(string bic)
6666
=> Regex.IsMatch(bic.Replace(" ", ""), @"^([a-zA-Z]{4}[a-zA-Z]{2}[a-zA-Z0-9]{2}([a-zA-Z0-9]{3})?)$");
6767

68+
/// <summary>
69+
/// Validates the structure of a BIC with optional requirement check.
70+
/// </summary>
71+
/// <param name="bic">The BIC to validate.</param>
72+
/// <param name="required">Whether the BIC is required. If false, null/empty values are considered valid.</param>
73+
/// <returns>True if the BIC is valid; otherwise, false.</returns>
74+
private static bool IsValidBic(string? bic, bool required)
75+
{
76+
if (string.IsNullOrEmpty(bic))
77+
return !required;
78+
return IsValidBic(bic!);
79+
}
6880

6981
/// <summary>
7082
/// Converts a string to a specified encoding.

QRCoder/PayloadGenerator/Girocode.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,16 +36,16 @@ public class Girocode : Payload
3636
/// <param name="version">Girocode version. Either 001 or 002. Default: 001.</param>
3737
/// <param name="encoding">Encoding of the Girocode payload. Default: ISO-8859-1</param>
3838
/// <exception cref="GirocodeException">Thrown when the input values are not valid according to the Girocode specification.</exception>
39-
public Girocode(string iban, string bic, string name, decimal amount, string remittanceInformation = "", TypeOfRemittance typeOfRemittance = TypeOfRemittance.Unstructured, string purposeOfCreditTransfer = "", string messageToGirocodeUser = "", GirocodeVersion version = GirocodeVersion.Version1, GirocodeEncoding encoding = GirocodeEncoding.ISO_8859_1)
39+
public Girocode(string iban, string? bic, string name, decimal amount, string remittanceInformation = "", TypeOfRemittance typeOfRemittance = TypeOfRemittance.Unstructured, string purposeOfCreditTransfer = "", string messageToGirocodeUser = "", GirocodeVersion version = GirocodeVersion.Version1, GirocodeEncoding encoding = GirocodeEncoding.ISO_8859_1)
4040
{
4141
_version = version;
4242
_encoding = encoding;
4343
if (!IsValidIban(iban))
4444
throw new GirocodeException("The IBAN entered isn't valid.");
4545
_iban = iban.Replace(" ", "").ToUpper();
46-
if (!IsValidBic(bic))
46+
if (!IsValidBic(bic, _version == GirocodeVersion.Version1))
4747
throw new GirocodeException("The BIC entered isn't valid.");
48-
_bic = bic.Replace(" ", "").ToUpper();
48+
_bic = bic?.Replace(" ", "").ToUpper() ?? string.Empty;
4949
if (name.Length > 70)
5050
throw new GirocodeException("(Payee-)Name must be shorter than 71 chars.");
5151
_name = name;

QRCoderApiTests/net35+net40+net50+net50-windows+netstandard20+netstandard21/QRCoder.approved.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -456,7 +456,7 @@ namespace QRCoder
456456
}
457457
public class Girocode : QRCoder.PayloadGenerator.Payload
458458
{
459-
public Girocode(string iban, string bic, string name, decimal amount, string remittanceInformation = "", QRCoder.PayloadGenerator.Girocode.TypeOfRemittance typeOfRemittance = 1, string purposeOfCreditTransfer = "", string messageToGirocodeUser = "", QRCoder.PayloadGenerator.Girocode.GirocodeVersion version = 0, QRCoder.PayloadGenerator.Girocode.GirocodeEncoding encoding = 1) { }
459+
public Girocode(string iban, string? bic, string name, decimal amount, string remittanceInformation = "", QRCoder.PayloadGenerator.Girocode.TypeOfRemittance typeOfRemittance = 1, string purposeOfCreditTransfer = "", string messageToGirocodeUser = "", QRCoder.PayloadGenerator.Girocode.GirocodeVersion version = 0, QRCoder.PayloadGenerator.Girocode.GirocodeEncoding encoding = 1) { }
460460
public override QRCoder.QRCodeGenerator.ECCLevel EccLevel { get; }
461461
public override string ToString() { }
462462
public enum GirocodeEncoding

QRCoderApiTests/net60-windows/QRCoder.approved.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -461,7 +461,7 @@ namespace QRCoder
461461
}
462462
public class Girocode : QRCoder.PayloadGenerator.Payload
463463
{
464-
public Girocode(string iban, string bic, string name, decimal amount, string remittanceInformation = "", QRCoder.PayloadGenerator.Girocode.TypeOfRemittance typeOfRemittance = 1, string purposeOfCreditTransfer = "", string messageToGirocodeUser = "", QRCoder.PayloadGenerator.Girocode.GirocodeVersion version = 0, QRCoder.PayloadGenerator.Girocode.GirocodeEncoding encoding = 1) { }
464+
public Girocode(string iban, string? bic, string name, decimal amount, string remittanceInformation = "", QRCoder.PayloadGenerator.Girocode.TypeOfRemittance typeOfRemittance = 1, string purposeOfCreditTransfer = "", string messageToGirocodeUser = "", QRCoder.PayloadGenerator.Girocode.GirocodeVersion version = 0, QRCoder.PayloadGenerator.Girocode.GirocodeEncoding encoding = 1) { }
465465
public override QRCoder.QRCodeGenerator.ECCLevel EccLevel { get; }
466466
public override string ToString() { }
467467
public enum GirocodeEncoding

QRCoderApiTests/net60/QRCoder.approved.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@ namespace QRCoder
419419
}
420420
public class Girocode : QRCoder.PayloadGenerator.Payload
421421
{
422-
public Girocode(string iban, string bic, string name, decimal amount, string remittanceInformation = "", QRCoder.PayloadGenerator.Girocode.TypeOfRemittance typeOfRemittance = 1, string purposeOfCreditTransfer = "", string messageToGirocodeUser = "", QRCoder.PayloadGenerator.Girocode.GirocodeVersion version = 0, QRCoder.PayloadGenerator.Girocode.GirocodeEncoding encoding = 1) { }
422+
public Girocode(string iban, string? bic, string name, decimal amount, string remittanceInformation = "", QRCoder.PayloadGenerator.Girocode.TypeOfRemittance typeOfRemittance = 1, string purposeOfCreditTransfer = "", string messageToGirocodeUser = "", QRCoder.PayloadGenerator.Girocode.GirocodeVersion version = 0, QRCoder.PayloadGenerator.Girocode.GirocodeEncoding encoding = 1) { }
423423
public override QRCoder.QRCodeGenerator.ECCLevel EccLevel { get; }
424424
public override string ToString() { }
425425
public enum GirocodeEncoding

QRCoderApiTests/netstandard13/QRCoder.approved.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ namespace QRCoder
399399
}
400400
public class Girocode : QRCoder.PayloadGenerator.Payload
401401
{
402-
public Girocode(string iban, string bic, string name, decimal amount, string remittanceInformation = "", QRCoder.PayloadGenerator.Girocode.TypeOfRemittance typeOfRemittance = 1, string purposeOfCreditTransfer = "", string messageToGirocodeUser = "", QRCoder.PayloadGenerator.Girocode.GirocodeVersion version = 0, QRCoder.PayloadGenerator.Girocode.GirocodeEncoding encoding = 1) { }
402+
public Girocode(string iban, string? bic, string name, decimal amount, string remittanceInformation = "", QRCoder.PayloadGenerator.Girocode.TypeOfRemittance typeOfRemittance = 1, string purposeOfCreditTransfer = "", string messageToGirocodeUser = "", QRCoder.PayloadGenerator.Girocode.GirocodeVersion version = 0, QRCoder.PayloadGenerator.Girocode.GirocodeEncoding encoding = 1) { }
403403
public override QRCoder.QRCodeGenerator.ECCLevel EccLevel { get; }
404404
public override string ToString() { }
405405
public enum GirocodeEncoding

QRCoderTests/PayloadGeneratorTests/GirocodeTests.cs

Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,4 +321,138 @@ public void girocode_generator_sets_encoding_parameters()
321321
payload.EciMode.ShouldBe<EciMode>(EciMode.Default);
322322
payload.Version.ShouldBe(-1);
323323
}
324+
325+
[Fact]
326+
public void girocode_generator_version2_with_null_bic_should_succeed()
327+
{
328+
var iban = "NL86INGB0002445588";
329+
var name = "a name";
330+
var remittanceInformation = "some info";
331+
var amount = 1337.99m;
332+
333+
var payload = new PayloadGenerator.Girocode(
334+
iban: iban,
335+
bic: null,
336+
name: name,
337+
amount: amount,
338+
remittanceInformation: remittanceInformation,
339+
version: PayloadGenerator.Girocode.GirocodeVersion.Version2,
340+
encoding: PayloadGenerator.Girocode.GirocodeEncoding.UTF_8);
341+
342+
payload
343+
.ToString()
344+
.ShouldBe("BCD\n002\n1\nSCT\n\na name\nNL86INGB0002445588\nEUR1337.99\n\n\nsome info\n");
345+
}
346+
347+
[Fact]
348+
public void girocode_generator_version2_with_empty_bic_should_succeed()
349+
{
350+
var iban = "NL86INGB0002445588";
351+
var name = "a name";
352+
var remittanceInformation = "some info";
353+
var amount = 1337.99m;
354+
355+
var payload = new PayloadGenerator.Girocode(
356+
iban: iban,
357+
bic: string.Empty,
358+
name: name,
359+
amount: amount,
360+
remittanceInformation: remittanceInformation,
361+
version: PayloadGenerator.Girocode.GirocodeVersion.Version2,
362+
encoding: PayloadGenerator.Girocode.GirocodeEncoding.UTF_8);
363+
364+
payload
365+
.ToString()
366+
.ShouldBe("BCD\n002\n1\nSCT\n\na name\nNL86INGB0002445588\nEUR1337.99\n\n\nsome info\n");
367+
}
368+
369+
[Fact]
370+
public void girocode_generator_version2_with_valid_bic_should_succeed()
371+
{
372+
var iban = "NL86INGB0002445588";
373+
var bic = "INGBNL2A";
374+
var name = "a name";
375+
var remittanceInformation = "some info";
376+
var amount = 1337.99m;
377+
378+
var payload = new PayloadGenerator.Girocode(
379+
iban: iban,
380+
bic: bic,
381+
name: name,
382+
amount: amount,
383+
remittanceInformation: remittanceInformation,
384+
version: PayloadGenerator.Girocode.GirocodeVersion.Version2,
385+
encoding: PayloadGenerator.Girocode.GirocodeEncoding.UTF_8);
386+
387+
payload
388+
.ToString()
389+
.ShouldBe("BCD\n002\n1\nSCT\nINGBNL2A\na name\nNL86INGB0002445588\nEUR1337.99\n\n\nsome info\n");
390+
}
391+
392+
[Fact]
393+
public void girocode_generator_version2_with_invalid_bic_should_throw_exception()
394+
{
395+
var iban = "NL86INGB0002445588";
396+
var bic = "INVALID";
397+
var name = "a name";
398+
var remittanceInformation = "some info";
399+
var amount = 1337.99m;
400+
401+
var exception = Record.Exception(() => new PayloadGenerator.Girocode(
402+
iban: iban,
403+
bic: bic,
404+
name: name,
405+
amount: amount,
406+
remittanceInformation: remittanceInformation,
407+
version: PayloadGenerator.Girocode.GirocodeVersion.Version2,
408+
encoding: PayloadGenerator.Girocode.GirocodeEncoding.UTF_8));
409+
410+
Assert.NotNull(exception);
411+
Assert.IsType<PayloadGenerator.Girocode.GirocodeException>(exception);
412+
exception.Message.ShouldBe("The BIC entered isn't valid.");
413+
}
414+
415+
[Fact]
416+
public void girocode_generator_version1_with_null_bic_should_throw_exception()
417+
{
418+
var iban = "NL86INGB0002445588";
419+
var name = "a name";
420+
var remittanceInformation = "some info";
421+
var amount = 1337.99m;
422+
423+
var exception = Record.Exception(() => new PayloadGenerator.Girocode(
424+
iban: iban,
425+
bic: null,
426+
name: name,
427+
amount: amount,
428+
remittanceInformation: remittanceInformation,
429+
version: PayloadGenerator.Girocode.GirocodeVersion.Version1,
430+
encoding: PayloadGenerator.Girocode.GirocodeEncoding.UTF_8));
431+
432+
Assert.NotNull(exception);
433+
Assert.IsType<PayloadGenerator.Girocode.GirocodeException>(exception);
434+
exception.Message.ShouldBe("The BIC entered isn't valid.");
435+
}
436+
437+
[Fact]
438+
public void girocode_generator_version1_with_empty_bic_should_throw_exception()
439+
{
440+
var iban = "NL86INGB0002445588";
441+
var name = "a name";
442+
var remittanceInformation = "some info";
443+
var amount = 1337.99m;
444+
445+
var exception = Record.Exception(() => new PayloadGenerator.Girocode(
446+
iban: iban,
447+
bic: string.Empty,
448+
name: name,
449+
amount: amount,
450+
remittanceInformation: remittanceInformation,
451+
version: PayloadGenerator.Girocode.GirocodeVersion.Version1,
452+
encoding: PayloadGenerator.Girocode.GirocodeEncoding.UTF_8));
453+
454+
Assert.NotNull(exception);
455+
Assert.IsType<PayloadGenerator.Girocode.GirocodeException>(exception);
456+
exception.Message.ShouldBe("The BIC entered isn't valid.");
457+
}
324458
}

0 commit comments

Comments
 (0)