diff --git a/README.md b/README.md index 90c7b1cf..7c19b3ba 100644 --- a/README.md +++ b/README.md @@ -500,6 +500,8 @@ In the examples above, all three alternative styles of using **Bogus** produce t * **`using Bogus.Extensions.Italy;`** * `Bogus.Person.CodiceFiscale()` - Codice Fiscale * `Bogus.DataSets.Finance.CodiceFiscale()` - Codice Fiscale +* **`using Bogus.Extensions.Netherlands;`** + * `Bogus.Vehicle.NlRegistrationPlate()` - Dutch Vehicle Registration Plate (kentekenplaat) * **`using Bogus.Extensions.Norway;`** * `Bogus.Person.Fodselsnummer()` - Norwegian national identity number * **`using Bogus.Extensions.Poland;`** diff --git a/Source/Bogus.Tests/ExtensionTests/DutchVehicleExtensionTests.cs b/Source/Bogus.Tests/ExtensionTests/DutchVehicleExtensionTests.cs new file mode 100644 index 00000000..7dedae59 --- /dev/null +++ b/Source/Bogus.Tests/ExtensionTests/DutchVehicleExtensionTests.cs @@ -0,0 +1,326 @@ +using System; +using Bogus.Extensions.Netherlands; +using FluentAssertions; +using Xunit; +using Xunit.Abstractions; + +namespace Bogus.Tests.ExtensionTests; + +public class DutchVehicleExtensionTests : SeededTest +{ + private readonly Faker faker; + private readonly ITestOutputHelper console; + + public DutchVehicleExtensionTests(ITestOutputHelper console) + { + faker = new Faker("nl"); + this.console = console; + } + + [Fact] + public void should_generate_valid_dutch_registration_plate() + { + // Arrange + var vehicle = faker.Vehicle; + var dateFrom = new DateTime(2020, 1, 1); + var dateTo = new DateTime(2024, 12, 31); + + // Act + var kenteken = vehicle.NlRegistrationPlate(dateFrom, dateTo); + + // Assert + kenteken.Should().NotBeNullOrEmpty(); + kenteken.Should().MatchRegex(@"^[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+$", "Dutch kenteken should follow the pattern with dashes"); + + console.WriteLine($"Generated kenteken: {kenteken}"); + } + + [Theory] + [InlineData("1951-01-01", "1964-12-31")] // Serie 1: XX-99-99 + [InlineData("1965-01-01", "1972-12-31")] // Serie 2: 99-99-XX + [InlineData("1973-01-01", "1977-12-31")] // Serie 3: 99-XX-99 + [InlineData("1978-07-01", "1990-12-31")] // Serie 4: XX-99-XX + [InlineData("1991-01-01", "1998-12-31")] // Serie 5: XX-XX-99 + [InlineData("1999-01-01", "2004-10-28")] // Serie 6: 99-XX-XX + [InlineData("2004-10-29", "2013-03-04")] // Serie 7: 99-XXX-9 + [InlineData("2013-03-05", "2015-03-29")] // Serie 8: 9-XXX-99 + [InlineData("2015-03-30", "2019-08-18")] // Serie 9: XX-999-X + [InlineData("2019-08-19", "2024-01-07")] // Serie 10: X-999-XX + [InlineData("2024-01-08", "2024-06-03")] // Serie 12: X-99-XXX (starts before Serie 11) + [InlineData("2024-06-04", "2024-12-31")] // Serie 11: XXX-99-X + public void should_generate_correct_format_for_date_ranges(string fromDate, string toDate) + { + // Arrange + var vehicle = faker.Vehicle; + var dateFrom = DateTime.Parse(fromDate); + var dateTo = DateTime.Parse(toDate); + + // Act + var kenteken = vehicle.NlRegistrationPlate(dateFrom, dateTo); + + // Assert + kenteken.Should().NotBeNullOrEmpty(); + ValidateKentekenFormatByDate(kenteken, dateFrom, dateTo); + + console.WriteLine($"Date range: {fromDate} to {toDate}, Generated kenteken: {kenteken}"); + } + + [Fact] + public void should_generate_serie_1_format_for_1950s() + { + // Arrange + var vehicle = faker.Vehicle; + var dateFrom = new DateTime(1951, 1, 1); + var dateTo = new DateTime(1964, 12, 31); + + // Act + var kenteken = vehicle.NlRegistrationPlate(dateFrom, dateTo); + + // Assert + kenteken.Should().MatchRegex(@"^[A-Z]{2}-\d{2}-\d{2}$", "Serie 1 should follow XX-99-99 format"); + + console.WriteLine($"Serie 1 kenteken: {kenteken}"); + } + + [Fact] + public void should_generate_serie_7_format_for_2000s() + { + // Arrange + var vehicle = faker.Vehicle; + var dateFrom = new DateTime(2004, 10, 29); + var dateTo = new DateTime(2013, 3, 4); + + // Act + var kenteken = vehicle.NlRegistrationPlate(dateFrom, dateTo); + + // Assert + kenteken.Should().MatchRegex(@"^\d{2}-[A-Z]{3}-\d{1}$", "Serie 7 should follow 99-XXX-9 format"); + + console.WriteLine($"Serie 7 kenteken: {kenteken}"); + } + + [Fact] + public void should_generate_serie_8_format_for_2010s() + { + // Arrange + var vehicle = faker.Vehicle; + var dateFrom = new DateTime(2013, 3, 5); + var dateTo = new DateTime(2015, 3, 29); + + // Act + var kenteken = vehicle.NlRegistrationPlate(dateFrom, dateTo); + + // Assert + kenteken.Should().MatchRegex(@"^\d{1}-[A-Z]{3}-\d{2}$", "Serie 8 should follow 9-XXX-99 format"); + + // Serie 8 for personenauto's should start with specific letters + var firstLetter = kenteken.Split('-')[1][0]; + new[] { 'K', 'S', 'T', 'X', 'Z' }.Should().Contain(firstLetter, "Serie 8 personenauto should start with K, S, T, X, or Z"); + + console.WriteLine($"Serie 8 kenteken: {kenteken}"); + } + + [Fact] + public void should_generate_current_format_for_recent_dates() + { + // Arrange + var vehicle = faker.Vehicle; + var dateFrom = new DateTime(2024, 6, 4); + var dateTo = new DateTime(2025, 12, 31); + + // Act + var kenteken = vehicle.NlRegistrationPlate(dateFrom, dateTo); + + // Assert + kenteken.Should().MatchRegex(@"^[A-Z]{3}-\d{2}-[A-Z]{1}$", "Current format should follow XXX-99-X format"); + + console.WriteLine($"Current kenteken: {kenteken}"); + } + + [Fact] + public void should_avoid_forbidden_combinations() + { + // Arrange + var vehicle = faker.Vehicle; + var dateFrom = new DateTime(2020, 1, 1); + var dateTo = new DateTime(2024, 12, 31); + + // Act & Assert - Generate multiple kentekens to test forbidden combinations + for (int i = 0; i < 100; i++) + { + var kenteken = vehicle.NlRegistrationPlate(dateFrom, dateTo); + + // Check that forbidden combinations are not present + kenteken.Should().NotContain("SA"); + kenteken.Should().NotContain("SD"); + kenteken.Should().NotContain("SS"); + kenteken.Should().NotContain("GVD"); + kenteken.Should().NotContain("KKK"); + kenteken.Should().NotContain("LPF"); + kenteken.Should().NotContain("NSB"); + kenteken.Should().NotContain("PKK"); + kenteken.Should().NotContain("PSV"); + kenteken.Should().NotContain("PVV"); + kenteken.Should().NotContain("TBS"); + kenteken.Should().NotContain("BBB"); + } + } + + [Fact] + public void should_generate_different_kentekens_for_different_vehicles() + { + // Arrange + var vehicle1 = faker.Vehicle; + var vehicle2 = faker.Vehicle; + var dateFrom = new DateTime(2020, 1, 1); + var dateTo = new DateTime(2024, 12, 31); + + // Act + var kenteken1 = vehicle1.NlRegistrationPlate(dateFrom, dateTo); + var kenteken2 = vehicle2.NlRegistrationPlate(dateFrom, dateTo); + + // Assert + kenteken1.Should().NotBe(kenteken2, "Different vehicles should have different kentekens"); + + console.WriteLine($"Vehicle 1 kenteken: {kenteken1}"); + console.WriteLine($"Vehicle 2 kenteken: {kenteken2}"); + } + + [Fact] + public void should_handle_date_swap_correctly() + { + // Arrange + var vehicle = faker.Vehicle; + var laterDate = new DateTime(2024, 12, 31); + var earlierDate = new DateTime(2020, 1, 1); + + // Act - Pass dates in wrong order + var kenteken = vehicle.NlRegistrationPlate(laterDate, earlierDate); + + // Assert + kenteken.Should().NotBeNullOrEmpty("Method should handle swapped dates gracefully"); + + console.WriteLine($"Kenteken with swapped dates: {kenteken}"); + } + + [Theory] + [InlineData("1950-12-31")] // Before earliest registration + [InlineData("2031-01-01")] // After latest registration + public void should_throw_exception_for_invalid_date_ranges(string invalidDate) + { + // Arrange + var vehicle = faker.Vehicle; + var validDate = new DateTime(2020, 1, 1); + var invalidDateTime = DateTime.Parse(invalidDate); + + // Act & Assert + Assert.Throws(() => vehicle.NlRegistrationPlate(invalidDateTime, validDate)); + Assert.Throws(() => vehicle.NlRegistrationPlate(validDate, invalidDateTime)); + } + + [Fact] + public void should_generate_valid_kentekens_consistently() + { + // Arrange + var vehicle = faker.Vehicle; + var dateFrom = new DateTime(2020, 1, 1); + var dateTo = new DateTime(2024, 12, 31); + + // Act & Assert - Generate multiple kentekens to ensure consistency + for (int i = 0; i < 100; i++) + { + var kenteken = vehicle.NlRegistrationPlate(dateFrom, dateTo); + + kenteken.Should().NotBeNullOrEmpty(); + kenteken.Should().MatchRegex(@"^[A-Z0-9]+-[A-Z0-9]+-[A-Z0-9]+$"); + kenteken.Split('-').Should().HaveCount(3, "Kenteken should have exactly 3 parts separated by dashes"); + } + } + + [Fact] + public void should_only_use_consonants_in_modern_formats() + { + // Arrange + var vehicle = faker.Vehicle; + var dateFrom = new DateTime(2004, 10, 29); // Serie 7 onwards + var dateTo = new DateTime(2024, 12, 31); + + // Act & Assert + for (int i = 0; i < 50; i++) + { + var kenteken = vehicle.NlRegistrationPlate(dateFrom, dateTo); + var parts = kenteken.Split('-'); + + foreach (var part in parts) + { + foreach (var character in part) + { + if (char.IsLetter(character)) + { + // Should not contain vowels (A, E, I, O, U) or forbidden letters + character.Should().NotBe('A'); + character.Should().NotBe('E'); + character.Should().NotBe('I'); + character.Should().NotBe('O'); + character.Should().NotBe('U'); + } + } + } + } + } + + private void ValidateKentekenFormatByDate(string kenteken, DateTime dateFrom, DateTime dateTo) + { + // Use the middle date of the range to determine expected format + var midDate = dateFrom.AddDays((dateTo - dateFrom).TotalDays / 2); + + if (midDate >= new DateTime(2024, 6, 4)) + { + kenteken.Should().MatchRegex(@"^[A-Z]{3}-\d{2}-[A-Z]{1}$", "Serie 11 format"); + } + else if (midDate >= new DateTime(2024, 1, 8)) + { + kenteken.Should().MatchRegex(@"^[A-Z]{1}-\d{2}-[A-Z]{3}$", "Serie 12 format"); + } + else if (midDate >= new DateTime(2019, 8, 19)) + { + kenteken.Should().MatchRegex(@"^[A-Z]{1}-\d{3}-[A-Z]{2}$", "Serie 10 format"); + } + else if (midDate >= new DateTime(2015, 3, 30)) + { + kenteken.Should().MatchRegex(@"^[A-Z]{2}-\d{3}-[A-Z]{1}$", "Serie 9 format"); + } + else if (midDate >= new DateTime(2013, 3, 5)) + { + kenteken.Should().MatchRegex(@"^\d{1}-[A-Z]{3}-\d{2}$", "Serie 8 format"); + } + else if (midDate >= new DateTime(2004, 10, 29)) + { + kenteken.Should().MatchRegex(@"^\d{2}-[A-Z]{3}-\d{1}$", "Serie 7 format"); + } + else if (midDate >= new DateTime(1999, 1, 1)) + { + kenteken.Should().MatchRegex(@"^\d{2}-[A-Z]{2}-[A-Z]{2}$", "Serie 6 format"); + } + else if (midDate >= new DateTime(1991, 1, 1)) + { + kenteken.Should().MatchRegex(@"^[A-Z]{2}-[A-Z]{2}-\d{2}$", "Serie 5 format"); + } + else if (midDate >= new DateTime(1978, 7, 1)) + { + kenteken.Should().MatchRegex(@"^[A-Z]{2}-\d{2}-[A-Z]{2}$", "Serie 4 format"); + } + else if (midDate >= new DateTime(1973, 1, 1)) + { + kenteken.Should().MatchRegex(@"^\d{2}-[A-Z]{2}-\d{2}$", "Serie 3 format"); + } + else if (midDate >= new DateTime(1965, 1, 1)) + { + kenteken.Should().MatchRegex(@"^\d{2}-\d{2}-[A-Z]{2}$", "Serie 2 format"); + } + else + { + kenteken.Should().MatchRegex(@"^[A-Z]{2}-\d{2}-\d{2}$", "Serie 1 format"); + } + } +} diff --git a/Source/Bogus/Extensions/Netherlands/VehicleExtensionsForNetherlands.cs b/Source/Bogus/Extensions/Netherlands/VehicleExtensionsForNetherlands.cs new file mode 100644 index 00000000..415839a7 --- /dev/null +++ b/Source/Bogus/Extensions/Netherlands/VehicleExtensionsForNetherlands.cs @@ -0,0 +1,264 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Bogus.DataSets; + +namespace Bogus.Extensions.Netherlands; + +/// +/// API extensions specific for a geographical location. +/// +public static class VehicleExtensionsForNetherlands +{ + // Dutch kenteken series with their date ranges and formats + private static readonly DateTime Serie1Start = new(1951, 1, 1); + private static readonly DateTime Serie2Start = new(1965, 1, 1); + private static readonly DateTime Serie3Start = new(1973, 1, 1); + private static readonly DateTime Serie4Start = new(1978, 7, 1); + private static readonly DateTime Serie5Start = new(1991, 1, 1); + private static readonly DateTime Serie6Start = new(1999, 1, 1); + private static readonly DateTime Serie7Start = new(2004, 10, 29); + private static readonly DateTime Serie8Start = new(2013, 3, 5); + private static readonly DateTime Serie9Start = new(2015, 3, 30); + private static readonly DateTime Serie10Start = new(2019, 8, 19); + private static readonly DateTime Serie11Start = new(2024, 6, 4); + private static readonly DateTime Serie12Start = new(2024, 1, 8); + + private static readonly DateTime EarliestRegistration = Serie1Start; + private static readonly DateTime LatestRegistration = new(2030, 12, 31); + + // Letters used in Dutch kentekens (excluding forbidden combinations) + private static readonly char[] ConsonantLetters = "BCDFGHJKLMNPRSTVWXZ".ToCharArray(); + private static readonly char[] AllLettersExceptKY = "BCDFGHJLMNPRSTVWXZ".ToCharArray(); // For serie 5 + private static readonly char[] AllLettersWithK = "BCDFGHJKLMNPRSTVWXZ".ToCharArray(); // For serie 6+ + + // Forbidden combinations that should be avoided + private static readonly HashSet ForbiddenCombinations = new() + { + "SA", "SD", "SS", "KL", "GVD", "KKK", "LPF", "NSB", "PKK", "PSV", "PVV", "TBS", "BBB" + }; + + /// + /// Dutch Vehicle Registration Plate (Kenteken) + /// + /// Object to extend. + /// The start of the range of registration dates. + /// The end of the range of registration dates. + /// A string containing a Dutch registration plate. + /// + /// This is based on the information in the Wikipedia article on + /// Dutch license plates (Nederlands kenteken). + /// https://nl.wikipedia.org/wiki/Nederlands_kenteken + /// Supports multiple kenteken series from 1951 to present. + /// + public static string NlRegistrationPlate(this Vehicle vehicle, DateTime dateFrom, DateTime dateTo) + { + DateTime registrationDate = GenerateRegistrationDate(vehicle, dateFrom, dateTo); + return GenerateKenteken(vehicle, registrationDate); + } + + private static string GenerateKenteken(Vehicle vehicle, DateTime registrationDate) + { + // Determine which serie to use based on registration date + // Note: Serie 11 starts later than Serie 12, so check it first + if (registrationDate >= Serie11Start) + return GenerateSerie11(vehicle); // XXX-99-X + else if (registrationDate >= Serie12Start) + return GenerateSerie12(vehicle); // X-99-XXX + else if (registrationDate >= Serie10Start) + return GenerateSerie10(vehicle); // X-999-XX + else if (registrationDate >= Serie9Start) + return GenerateSerie9(vehicle); // XX-999-X + else if (registrationDate >= Serie8Start) + return GenerateSerie8(vehicle); // 9-XXX-99 + else if (registrationDate >= Serie7Start) + return GenerateSerie7(vehicle); // 99-XXX-9 + else if (registrationDate >= Serie6Start) + return GenerateSerie6(vehicle); // 99-XX-XX + else if (registrationDate >= Serie5Start) + return GenerateSerie5(vehicle); // XX-XX-99 + else if (registrationDate >= Serie4Start) + return GenerateSerie4(vehicle); // XX-99-XX + else if (registrationDate >= Serie3Start) + return GenerateSerie3(vehicle); // 99-XX-99 + else if (registrationDate >= Serie2Start) + return GenerateSerie2(vehicle); // 99-99-XX + else + return GenerateSerie1(vehicle); // XX-99-99 + } + + private static string GenerateSerie1(Vehicle vehicle) + { + // XX-99-99 format, started with ND-00-01 + string firstLetter = vehicle.Random.ArrayElement(new[] { "N", "P", "R", "S", "T", "V", "X", "Z" }); + string secondLetter = vehicle.Random.ArrayElement(new[] { "D", "G", "K", "P", "T", "X" }); // Personenauto letters + string numbers1 = vehicle.Random.Int(0, 99).ToString("D2"); + string numbers2 = vehicle.Random.Int(1, 99).ToString("D2"); + return $"{firstLetter}{secondLetter}-{numbers1}-{numbers2}"; + } + + private static string GenerateSerie2(Vehicle vehicle) + { + // 99-99-XX format + string numbers1 = vehicle.Random.Int(10, 99).ToString("D2"); + string numbers2 = vehicle.Random.Int(1, 99).ToString("D2"); + string letters = GenerateRandomLetterPair(vehicle, ConsonantLetters); + return $"{numbers1}-{numbers2}-{letters}"; + } + + private static string GenerateSerie3(Vehicle vehicle) + { + // 99-XX-99 format + string numbers1 = vehicle.Random.Int(10, 99).ToString("D2"); + string letters = GenerateRandomLetterPair(vehicle, ConsonantLetters); + string numbers2 = vehicle.Random.Int(1, 99).ToString("D2"); + return $"{numbers1}-{letters}-{numbers2}"; + } + + private static string GenerateSerie4(Vehicle vehicle) + { + // XX-99-XX format + string letters1 = GenerateRandomLetterPair(vehicle, ConsonantLetters); + string numbers = vehicle.Random.Int(1, 99).ToString("D2"); + string letters2 = GenerateRandomLetterPair(vehicle, ConsonantLetters); + return $"{letters1}-{numbers}-{letters2}"; + } + + private static string GenerateSerie5(Vehicle vehicle) + { + // XX-XX-99 format (no K or Y) + string letters1 = GenerateRandomLetterPair(vehicle, AllLettersExceptKY); + string letters2 = GenerateRandomLetterPair(vehicle, AllLettersExceptKY); + string numbers = vehicle.Random.Int(1, 99).ToString("D2"); + return $"{letters1}-{letters2}-{numbers}"; + } + + private static string GenerateSerie6(Vehicle vehicle) + { + // 99-XX-XX format (K is back except as first letter) + string numbers = vehicle.Random.Int(1, 99).ToString("D2"); + string letters1 = GenerateRandomLetterPair(vehicle, AllLettersWithK); + string letters2 = GenerateRandomLetterPair(vehicle, AllLettersWithK); + return $"{numbers}-{letters1}-{letters2}"; + } + + private static string GenerateSerie7(Vehicle vehicle) + { + // 99-XXX-9 format + string numbers1 = vehicle.Random.Int(0, 99).ToString("D2"); + string letters = GenerateRandomLetterTriple(vehicle, ConsonantLetters); + string numbers2 = vehicle.Random.Int(1, 9).ToString(); + return $"{numbers1}-{letters}-{numbers2}"; + } + + private static string GenerateSerie8(Vehicle vehicle) + { + // 9-XXX-99 format (personenauto's: K, S, T, X, Z) + string[] validFirstLetters = { "K", "S", "T", "X", "Z" }; + string firstLetter = vehicle.Random.ArrayElement(validFirstLetters); + string remainingLetters = GenerateRandomLetterPair(vehicle, ConsonantLetters); + string numbers1 = vehicle.Random.Int(1, 9).ToString(); + string numbers2 = vehicle.Random.Int(0, 99).ToString("D2"); + return $"{numbers1}-{firstLetter}{remainingLetters}-{numbers2}"; + } + + private static string GenerateSerie9(Vehicle vehicle) + { + // XX-999-X format + string letters1 = GenerateRandomLetterPair(vehicle, ConsonantLetters); + string numbers = vehicle.Random.Int(1, 999).ToString("D3"); + string letter2 = vehicle.Random.ArrayElement(ConsonantLetters).ToString(); + return $"{letters1}-{numbers}-{letter2}"; + } + + private static string GenerateSerie10(Vehicle vehicle) + { + // X-999-XX format + string letter1 = vehicle.Random.ArrayElement(ConsonantLetters).ToString(); + string numbers = vehicle.Random.Int(1, 999).ToString("D3"); + string letters2 = GenerateRandomLetterPair(vehicle, ConsonantLetters); + return $"{letter1}-{numbers}-{letters2}"; + } + + private static string GenerateSerie11(Vehicle vehicle) + { + // XXX-99-X format + string letters1 = GenerateRandomLetterTriple(vehicle, ConsonantLetters); + string numbers = vehicle.Random.Int(1, 99).ToString("D2"); + string letter2 = vehicle.Random.ArrayElement(ConsonantLetters).ToString(); + return $"{letters1}-{numbers}-{letter2}"; + } + + private static string GenerateSerie12(Vehicle vehicle) + { + // X-99-XXX format + string letter1 = vehicle.Random.ArrayElement(ConsonantLetters).ToString(); + string numbers = vehicle.Random.Int(1, 99).ToString("D2"); + string letters2 = GenerateRandomLetterTriple(vehicle, ConsonantLetters); + return $"{letter1}-{numbers}-{letters2}"; + } + + private static string GenerateRandomLetterPair(Vehicle vehicle, char[] availableLetters) + { + string result; + int attempts = 0; + do + { + char letter1 = vehicle.Random.ArrayElement(availableLetters); + char letter2 = vehicle.Random.ArrayElement(availableLetters); + result = $"{letter1}{letter2}"; + attempts++; + } while (ForbiddenCombinations.Contains(result) && attempts < 100); + + return result; + } + + private static string GenerateRandomLetterTriple(Vehicle vehicle, char[] availableLetters) + { + string result; + int attempts = 0; + do + { + char letter1 = vehicle.Random.ArrayElement(availableLetters); + char letter2 = vehicle.Random.ArrayElement(availableLetters); + char letter3 = vehicle.Random.ArrayElement(availableLetters); + result = $"{letter1}{letter2}{letter3}"; + attempts++; + } while (ContainsForbiddenSubstring(result) && attempts < 100); + + return result; + } + + private static bool ContainsForbiddenSubstring(string letters) + { + foreach (string forbidden in ForbiddenCombinations) + { + if (letters.Contains(forbidden)) + return true; + } + return false; + } + + private static DateTime GenerateRegistrationDate(Vehicle vehicle, DateTime dateFrom, DateTime dateTo) + { + if (dateFrom < EarliestRegistration || dateFrom > LatestRegistration) + throw new ArgumentOutOfRangeException(nameof(dateFrom), $"Can only accept registration dates between {EarliestRegistration:yyyy-MM-dd} and {LatestRegistration:yyyy-MM-dd}."); + if (dateTo < EarliestRegistration || dateTo > LatestRegistration) + throw new ArgumentOutOfRangeException(nameof(dateTo), $"Can only accept registration dates between {EarliestRegistration:yyyy-MM-dd} and {LatestRegistration:yyyy-MM-dd}."); + + // Swap the values if they're the wrong way around + if (dateFrom > dateTo) + { + DateTime valueHolder = dateFrom; + dateFrom = dateTo; + dateTo = valueHolder; + } + + dateFrom = dateFrom.Date; + dateTo = dateTo.Date; + int duration = (int)(dateTo - dateFrom).TotalDays; + int offset = vehicle.Random.Int(0, duration); + DateTime registrationDate = dateFrom.AddDays(offset); + return registrationDate; + } +} \ No newline at end of file diff --git a/Source/Bogus/data/nl.locale.json b/Source/Bogus/data/nl.locale.json index 4c19f499..1c521546 100644 --- a/Source/Bogus/data/nl.locale.json +++ b/Source/Bogus/data/nl.locale.json @@ -2857,7 +2857,15 @@ "#{street_name} #{building_number}" ], "postcode": [ - "#### ??" + "1### ??", + "2### ??", + "3### ??", + "4### ??", + "5### ??", + "6### ??", + "7### ??", + "8### ??", + "9### ??" ], "state": [ "Noord-Holland", @@ -4729,9 +4737,11 @@ }, "phone_number": { "formats": [ - "(####) ######", - "##########", + "0###-######", + "0##-#######", + "0#########", "06########", + "06-########", "06 #### ####" ] } diff --git a/Source/Bogus/data/nl.locale.schema.verified.txt b/Source/Bogus/data/nl.locale.schema.verified.txt index 8674e5f5..c82da10a 100644 --- a/Source/Bogus/data/nl.locale.schema.verified.txt +++ b/Source/Bogus/data/nl.locale.schema.verified.txt @@ -6,7 +6,7 @@ city_suffix: [Array String; 47], country: [Array String; 254], default_country: [Array String; 1], - postcode: [Array String; 1], + postcode: [Array String; 9], secondary_address: [Array String; 4], state: [Array String; 12], street_address: [Array String; 1], @@ -63,7 +63,7 @@ tussenvoegsel: [Array String; 7] }, phone_number: { - formats: [Array String; 4] + formats: [Array String; 6] }, title: Dutch } \ No newline at end of file