Skip to content

Commit

Permalink
Closes #6114
Browse files Browse the repository at this point in the history
Add support for Bosnia and Herzegovina phone numbers
  • Loading branch information
TrevorPilley authored Apr 15, 2024
1 parent 75cd60b commit 7dabbf4
Show file tree
Hide file tree
Showing 9 changed files with 369 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ Country | ISO 3166 Code | Calling Code | Trunk Prefix | Geographic | Mobi
Austria | AT | 43 | 0 | Yes | Yes | | | Yes | Yes | Yes | |
Belarus | BY | 375 | 8 | Yes | Yes | | | Yes | Yes | Yes | |
Belgium | BE | 32 | 0 | Yes | Yes | | | Yes | Yes | Yes | | Yes
Bosnia and Herzegovina | BA | 387 | 0 | Yes | Yes | | Yes | Yes | Yes | Yes | Yes | Yes
Bulgaria | BG | 359 | 0 | Yes | Yes | | Yes | Yes | Yes | Yes | | Yes
Croatia | HR | 385 | 0 | Yes | Yes | | Yes | Yes | Yes | Yes | | Yes
Cyprus | CY | 387 | | Yes | Yes | | Yes | Yes | Yes | Yes | Yes | Yes
Expand Down
14 changes: 14 additions & 0 deletions src/PhoneNumbers/CountryInfo_Europe.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,20 @@ public partial class CountryInfo
TrunkPrefix = "0",
};

/// <summary>
/// Gets the <see cref="CountryInfo"/> for Bosnia and Herzegovina.
/// </summary>
public static CountryInfo BosniaAndHerzegovina { get; } = new()
{
CallingCode = "387",
Continent = Europe,
Iso3166Code = "BA",
Name = "Bosnia and Herzegovina",
NdcLengths = new ReadOnlyCollection<int>([4, 3, 2]),
NsnLengths = new ReadOnlyCollection<int>([6, 8, 9]),
TrunkPrefix = "0",
};

/// <summary>
/// Gets the <see cref="CountryInfo"/> for Bulgaria.
/// </summary>
Expand Down
34 changes: 34 additions & 0 deletions src/PhoneNumbers/DataFiles/BA.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# References:
# - https://www.itu.int/dms_pub/itu-t/oth/02/02/T020200001B0001PDFE.pdf
G|30|Central Bosnia Canton|000000-999999|
G|31|Posavina Canton|000000-999999|
G|32|Zenica-Doboj Canton|000000-999999|
G|33|Sarajevo Canton|000000-999999|
G|34|Canton 10|000000-999999|
G|35|Tuzla Canton|000000-999999|
G|36|Hercegovina-Neretva Canton|000000-999999|
G|37|Unsa-Sana Canton|000000-999999|
G|38|Bosanian-Podrinje Goražde Canton|000000-999999|
G|39|West Herzegovina Canton|000000-999999|
G|49|Brčko Distirct B&H|000000-999999|
G|50|Mrkonjić Grad|000000-999999|
G|51|Banja Luka|000000-999999|
G|52|Prijedor|000000-999999|
G|53|Doboj|000000-999999|
G|54|Šamac|000000-999999|
G|55|Bijeljina|000000-999999|
G|56|Zvornik|000000-999999|
G|57|Istočno Sarajevo|000000-999999|
G|58|Foča|000000-999999|
G|59|Trebinje|000000-999999|
M|60,64,67||0000000-9999999|
M|61-63,65-66||000000-999999|
N|70||000000-099999|V
N|800||00000-99999|F
N|8010||0000-9999|
N|810-818||000000-999999|S
N|819||00000-99999|
N|82||000000-999999|S
N|83||0000-9999|
N|85||0000000-9999999|M
N|90-92,94,96||000000-999999|R
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
namespace PhoneNumbers.Tests.Parsers;

/// <summary>
/// Contains unit tests for the <see cref="DefaultPhoneNumberParser"/> class for Bosnia and herzegovina <see cref="PhoneNumber"/>s.
/// </summary>
public class DefaultPhoneNumberParserTests_BA_GeographicNumber
{
private static readonly PhoneNumberParser s_parser = DefaultPhoneNumberParser.Create(CountryInfo.BosniaAndHerzegovina);

[Theory]
[InlineData("030000000", "30", "000000", "Central Bosnia Canton")]
[InlineData("030999999", "30", "999999", "Central Bosnia Canton")]
[InlineData("031000000", "31", "000000", "Posavina Canton")]
[InlineData("031999999", "31", "999999", "Posavina Canton")]
[InlineData("032000000", "32", "000000", "Zenica-Doboj Canton")]
[InlineData("032999999", "32", "999999", "Zenica-Doboj Canton")]
[InlineData("033000000", "33", "000000", "Sarajevo Canton")]
[InlineData("033999999", "33", "999999", "Sarajevo Canton")]
[InlineData("034000000", "34", "000000", "Canton 10")]
[InlineData("034999999", "34", "999999", "Canton 10")]
[InlineData("035000000", "35", "000000", "Tuzla Canton")]
[InlineData("035999999", "35", "999999", "Tuzla Canton")]
[InlineData("036000000", "36", "000000", "Hercegovina-Neretva Canton")]
[InlineData("036999999", "36", "999999", "Hercegovina-Neretva Canton")]
[InlineData("037000000", "37", "000000", "Unsa-Sana Canton")]
[InlineData("037999999", "37", "999999", "Unsa-Sana Canton")]
[InlineData("038000000", "38", "000000", "Bosanian-Podrinje Goražde Canton")]
[InlineData("038999999", "38", "999999", "Bosanian-Podrinje Goražde Canton")]
[InlineData("039000000", "39", "000000", "West Herzegovina Canton")]
[InlineData("039999999", "39", "999999", "West Herzegovina Canton")]
public void Parse_Known_GeographicPhoneNumber_3X_NationalDestinationCode(string value, string NationalDestinationCode, string subscriberNumber, string geographicArea)
{
var parseResult = s_parser.Parse(value);
parseResult.ThrowIfFailure();

var phoneNumber = parseResult.PhoneNumber;

Assert.NotNull(phoneNumber);
Assert.IsType<GeographicPhoneNumber>(phoneNumber);

var geographicPhoneNumber = (GeographicPhoneNumber)phoneNumber;
Assert.Equal(CountryInfo.BosniaAndHerzegovina, geographicPhoneNumber.Country);
Assert.Equal(geographicArea, geographicPhoneNumber.GeographicArea);
Assert.Equal(NationalDestinationCode, geographicPhoneNumber.NationalDestinationCode);
Assert.Equal(subscriberNumber, geographicPhoneNumber.SubscriberNumber);
}

[Theory]
[InlineData("049000000", "49", "000000", "Brčko Distirct B&H")]
[InlineData("049999999", "49", "999999", "Brčko Distirct B&H")]
public void Parse_Known_GeographicPhoneNumber_4X_NationalDestinationCode(string value, string NationalDestinationCode, string subscriberNumber, string geographicArea)
{
var parseResult = s_parser.Parse(value);
parseResult.ThrowIfFailure();

var phoneNumber = parseResult.PhoneNumber;

Assert.NotNull(phoneNumber);
Assert.IsType<GeographicPhoneNumber>(phoneNumber);

var geographicPhoneNumber = (GeographicPhoneNumber)phoneNumber;
Assert.Equal(CountryInfo.BosniaAndHerzegovina, geographicPhoneNumber.Country);
Assert.Equal(geographicArea, geographicPhoneNumber.GeographicArea);
Assert.Equal(NationalDestinationCode, geographicPhoneNumber.NationalDestinationCode);
Assert.Equal(subscriberNumber, geographicPhoneNumber.SubscriberNumber);
}

[Theory]
[InlineData("050000000", "50", "000000", "Mrkonjić Grad")]
[InlineData("050999999", "50", "999999", "Mrkonjić Grad")]
[InlineData("051000000", "51", "000000", "Banja Luka")]
[InlineData("051999999", "51", "999999", "Banja Luka")]
[InlineData("052000000", "52", "000000", "Prijedor")]
[InlineData("052999999", "52", "999999", "Prijedor")]
[InlineData("053000000", "53", "000000", "Doboj")]
[InlineData("053999999", "53", "999999", "Doboj")]
[InlineData("054000000", "54", "000000", "Šamac")]
[InlineData("054999999", "54", "999999", "Šamac")]
[InlineData("055000000", "55", "000000", "Bijeljina")]
[InlineData("055999999", "55", "999999", "Bijeljina")]
[InlineData("056000000", "56", "000000", "Zvornik")]
[InlineData("056999999", "56", "999999", "Zvornik")]
[InlineData("057000000", "57", "000000", "Istočno Sarajevo")]
[InlineData("057999999", "57", "999999", "Istočno Sarajevo")]
[InlineData("058000000", "58", "000000", "Foča")]
[InlineData("058999999", "58", "999999", "Foča")]
[InlineData("059000000", "59", "000000", "Trebinje")]
[InlineData("059999999", "59", "999999", "Trebinje")]
public void Parse_Known_GeographicPhoneNumber_5X_NationalDestinationCode(string value, string NationalDestinationCode, string subscriberNumber, string geographicArea)
{
var parseResult = s_parser.Parse(value);
parseResult.ThrowIfFailure();

var phoneNumber = parseResult.PhoneNumber;

Assert.NotNull(phoneNumber);
Assert.IsType<GeographicPhoneNumber>(phoneNumber);

var geographicPhoneNumber = (GeographicPhoneNumber)phoneNumber;
Assert.Equal(CountryInfo.BosniaAndHerzegovina, geographicPhoneNumber.Country);
Assert.Equal(geographicArea, geographicPhoneNumber.GeographicArea);
Assert.Equal(NationalDestinationCode, geographicPhoneNumber.NationalDestinationCode);
Assert.Equal(subscriberNumber, geographicPhoneNumber.SubscriberNumber);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace PhoneNumbers.Tests.Parsers;

/// <summary>
/// Contains unit tests for the <see cref="DefaultPhoneNumberParser"/> class for Bosnia and herzegovina <see cref="PhoneNumber"/>s.
/// </summary>
public class DefaultPhoneNumberParserTests_BA_MobilePhoneNumber
{
private static readonly PhoneNumberParser s_parser = DefaultPhoneNumberParser.Create(CountryInfo.BosniaAndHerzegovina);

[Theory]
[InlineData("0600000000", "60", "0000000")]
[InlineData("0609999999", "60", "9999999")]
[InlineData("061000000", "61", "000000")]
[InlineData("061999999", "61", "999999")]
[InlineData("063000000", "63", "000000")]
[InlineData("063999999", "63", "999999")]
[InlineData("0640000000", "64", "0000000")]
[InlineData("0649999999", "64", "9999999")]
[InlineData("065000000", "65", "000000")]
[InlineData("065999999", "65", "999999")]
[InlineData("066000000", "66", "000000")]
[InlineData("066999999", "66", "999999")]
[InlineData("0670000000", "67", "0000000")]
[InlineData("0679999999", "67", "9999999")]
public void Parse_Known_MobilePhoneNumber(string value, string NationalDestinationCode, string subscriberNumber)
{
var parseResult = s_parser.Parse(value);
parseResult.ThrowIfFailure();

var phoneNumber = parseResult.PhoneNumber;

Assert.NotNull(phoneNumber);
Assert.IsType<MobilePhoneNumber>(phoneNumber);

var mobilePhoneNumber = (MobilePhoneNumber)phoneNumber;
Assert.Equal(CountryInfo.BosniaAndHerzegovina, mobilePhoneNumber.Country);
Assert.False(mobilePhoneNumber.IsPager);
Assert.False(mobilePhoneNumber.IsVirtual);
Assert.Equal(NationalDestinationCode, mobilePhoneNumber.NationalDestinationCode);
Assert.Equal(subscriberNumber, mobilePhoneNumber.SubscriberNumber);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
namespace PhoneNumbers.Tests.Parsers;

/// <summary>
/// Contains unit tests for the <see cref="DefaultPhoneNumberParser"/> class for Bosnia and herzegovina <see cref="PhoneNumber"/>s.
/// </summary>
public class DefaultPhoneNumberParserTests_BA_NonGeographicPhoneNumber
{
private static readonly PhoneNumberParser s_parser = DefaultPhoneNumberParser.Create(CountryInfo.BosniaAndHerzegovina);

[Theory]
[InlineData("080100000", "8010", "0000")]
[InlineData("080109999", "8010", "9999")]
[InlineData("081900000", "819", "00000")]
[InlineData("081999999", "819", "99999")]
[InlineData("0830000", "83", "0000")]
[InlineData("0839999", "83", "9999")]
public void Parse_Known_NonGeographicPhoneNumber_8XXX_NationalDestinationCode(string value, string NationalDestinationCode, string subscriberNumber)
{
var parseResult = s_parser.Parse(value);
parseResult.ThrowIfFailure();

var phoneNumber = parseResult.PhoneNumber;

Assert.NotNull(phoneNumber);
Assert.IsType<NonGeographicPhoneNumber>(phoneNumber);

var nonGeographicPhoneNumber = (NonGeographicPhoneNumber)phoneNumber;
Assert.Equal(CountryInfo.BosniaAndHerzegovina, nonGeographicPhoneNumber.Country);
Assert.False(nonGeographicPhoneNumber.IsFreephone);
Assert.False(nonGeographicPhoneNumber.IsMachineToMachine);
Assert.False(nonGeographicPhoneNumber.IsPremiumRate);
Assert.False(nonGeographicPhoneNumber.IsSharedCost);
Assert.Equal(NationalDestinationCode, nonGeographicPhoneNumber.NationalDestinationCode);
Assert.Equal(subscriberNumber, nonGeographicPhoneNumber.SubscriberNumber);
}

[Theory]
[InlineData("080000000", "800", "00000")]
[InlineData("080099999", "800", "99999")]
public void Parse_Known_NonGeographicPhoneNumber_Freephone(string value, string NationalDestinationCode, string subscriberNumber)
{
var parseResult = s_parser.Parse(value);
parseResult.ThrowIfFailure();

var phoneNumber = parseResult.PhoneNumber;

Assert.NotNull(phoneNumber);
Assert.IsType<NonGeographicPhoneNumber>(phoneNumber);

var nonGeographicPhoneNumber = (NonGeographicPhoneNumber)phoneNumber;
Assert.Equal(CountryInfo.BosniaAndHerzegovina, nonGeographicPhoneNumber.Country);
Assert.True(nonGeographicPhoneNumber.IsFreephone);
Assert.False(nonGeographicPhoneNumber.IsMachineToMachine);
Assert.False(nonGeographicPhoneNumber.IsPremiumRate);
Assert.False(nonGeographicPhoneNumber.IsSharedCost);
Assert.Equal(NationalDestinationCode, nonGeographicPhoneNumber.NationalDestinationCode);
Assert.Equal(subscriberNumber, nonGeographicPhoneNumber.SubscriberNumber);
}

[Theory]
[InlineData("0850000000", "85", "0000000")]
[InlineData("0859999999", "85", "9999999")]
public void Parse_Known_NonGeographicPhoneNumber_MachineToMachine(string value, string NationalDestinationCode, string subscriberNumber)
{
var parseResult = s_parser.Parse(value);
parseResult.ThrowIfFailure();

var phoneNumber = parseResult.PhoneNumber;

Assert.NotNull(phoneNumber);
Assert.IsType<NonGeographicPhoneNumber>(phoneNumber);

var nonGeographicPhoneNumber = (NonGeographicPhoneNumber)phoneNumber;
Assert.Equal(CountryInfo.BosniaAndHerzegovina, nonGeographicPhoneNumber.Country);
Assert.False(nonGeographicPhoneNumber.IsFreephone);
Assert.True(nonGeographicPhoneNumber.IsMachineToMachine);
Assert.False(nonGeographicPhoneNumber.IsPremiumRate);
Assert.False(nonGeographicPhoneNumber.IsSharedCost);
Assert.Equal(NationalDestinationCode, nonGeographicPhoneNumber.NationalDestinationCode);
Assert.Equal(subscriberNumber, nonGeographicPhoneNumber.SubscriberNumber);
}

[Theory]
[InlineData("090000000", "90", "000000")]
[InlineData("090999999", "90", "999999")]
[InlineData("092000000", "92", "000000")]
[InlineData("092999999", "92", "999999")]
[InlineData("094000000", "94", "000000")]
[InlineData("094999999", "94", "999999")]
[InlineData("096000000", "96", "000000")]
[InlineData("096999999", "96", "999999")]
public void Parse_Known_NonGeographicPhoneNumber_PremiumRate(string value, string NationalDestinationCode, string subscriberNumber)
{
var parseResult = s_parser.Parse(value);
parseResult.ThrowIfFailure();

var phoneNumber = parseResult.PhoneNumber;

Assert.NotNull(phoneNumber);
Assert.IsType<NonGeographicPhoneNumber>(phoneNumber);

var nonGeographicPhoneNumber = (NonGeographicPhoneNumber)phoneNumber;
Assert.Equal(CountryInfo.BosniaAndHerzegovina, nonGeographicPhoneNumber.Country);
Assert.False(nonGeographicPhoneNumber.IsFreephone);
Assert.False(nonGeographicPhoneNumber.IsMachineToMachine);
Assert.True(nonGeographicPhoneNumber.IsPremiumRate);
Assert.False(nonGeographicPhoneNumber.IsSharedCost);
Assert.Equal(NationalDestinationCode, nonGeographicPhoneNumber.NationalDestinationCode);
Assert.Equal(subscriberNumber, nonGeographicPhoneNumber.SubscriberNumber);
}

[Theory]
[InlineData("0810000000", "810", "000000")]
[InlineData("0810999999", "810", "999999")]
[InlineData("0818000000", "818", "000000")]
[InlineData("0818999999", "818", "999999")]
[InlineData("082000000", "82", "000000")]
[InlineData("082999999", "82", "999999")]
public void Parse_Known_NonGeographicPhoneNumber_SharedCost(string value, string NationalDestinationCode, string subscriberNumber)
{
var parseResult = s_parser.Parse(value);
parseResult.ThrowIfFailure();

var phoneNumber = parseResult.PhoneNumber;

Assert.NotNull(phoneNumber);
Assert.IsType<NonGeographicPhoneNumber>(phoneNumber);

var nonGeographicPhoneNumber = (NonGeographicPhoneNumber)phoneNumber;
Assert.Equal(CountryInfo.BosniaAndHerzegovina, nonGeographicPhoneNumber.Country);
Assert.False(nonGeographicPhoneNumber.IsFreephone);
Assert.False(nonGeographicPhoneNumber.IsMachineToMachine);
Assert.False(nonGeographicPhoneNumber.IsPremiumRate);
Assert.True(nonGeographicPhoneNumber.IsSharedCost);
Assert.Equal(NationalDestinationCode, nonGeographicPhoneNumber.NationalDestinationCode);
Assert.Equal(subscriberNumber, nonGeographicPhoneNumber.SubscriberNumber);
}
}
20 changes: 20 additions & 0 deletions test/PhoneNumbers.Tests/CountryInfo_Europe_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,26 @@ public void CountryInfo_Belgium()
Assert.Equal("0", countryInfo.TrunkPrefix);
}

[Fact]
public void CountryInfo_BosniaAndHerzegovina()
{
Assert.Same(CountryInfo.BosniaAndHerzegovina, CountryInfo.BosniaAndHerzegovina);

var countryInfo = CountryInfo.BosniaAndHerzegovina;

Assert.False(countryInfo.AllowsLocalGeographicDialling);
Assert.Equal("387", countryInfo.CallingCode);
Assert.Equal(CountryInfo.Europe, countryInfo.Continent);
Assert.IsType<ComplexPhoneNumberFormatProvider>(countryInfo.FormatProvider);
Assert.False(countryInfo.IsEuropeanUnionMember);
Assert.Equal("BA", countryInfo.Iso3166Code);
Assert.Equal("Bosnia and Herzegovina", countryInfo.Name);
Assert.Equal(new[] { 4, 3, 2 }, countryInfo.NdcLengths);
Assert.Equal(new[] { 6, 8, 9 }, countryInfo.NsnLengths);
Assert.False(countryInfo.SharesCallingCode);
Assert.Equal("0", countryInfo.TrunkPrefix);
}

[Fact]
public void CountryInfo_Bulgaria()
{
Expand Down
8 changes: 8 additions & 0 deletions test/PhoneNumbers.Tests/PhoneNumber_Parse_Europe_Tests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,14 @@ public void Parse_Value_For_Belgium_CallingCode()
Assert.Equal(CountryInfo.Belgium, phoneNumber.Country);
}

[Fact]
public void Parse_Value_For_BosniaAndHerzegovina_CallingCode()
{
var phoneNumber = PhoneNumber.Parse("+38733250600");
Assert.NotNull(phoneNumber);
Assert.Equal(CountryInfo.BosniaAndHerzegovina, phoneNumber.Country);
}

[Fact]
public void Parse_Value_For_Bulgaria_CallingCode()
{
Expand Down
Loading

0 comments on commit 7dabbf4

Please sign in to comment.