summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/RegistrationNumber.php68
-rw-r--r--tests/RegistrationNumberTest.php96
2 files changed, 159 insertions, 5 deletions
diff --git a/src/RegistrationNumber.php b/src/RegistrationNumber.php
index 3f6edcc..3e284ed 100644
--- a/src/RegistrationNumber.php
+++ b/src/RegistrationNumber.php
@@ -224,6 +224,42 @@ final readonly class RegistrationNumber
private static function checkSequenceForCleanEnergy(string $sequence): bool
{
$sequence = mb_strtoupper($sequence);
+
+ $last = mb_substr($sequence, -1);
+ $codepoint = mb_ord($last);
+
+ if (is_int($codepoint) && $codepoint >= ord('A') && $codepoint <= ord('Z')) {
+ return static::checkSequenceForLargeCleanEnergy($sequence);
+ }
+
+ return static::checkSequenceForSmallCleanEnergy($sequence);
+ }
+
+ private static function checkSequenceForLargeCleanEnergy(string $sequence): bool
+ {
+ $last = mb_substr($sequence, -1);
+
+ if (! in_array($last, self::CLEAN_ENERGY_FIRST_LETTERS)) {
+ return false;
+ }
+
+ for ($i = 0; $i < mb_strlen($sequence) - 1; $i++) {
+ $codepoint = mb_ord($sequence[$i]);
+
+ if ($codepoint === false) {
+ return false;
+ }
+
+ if ($codepoint < ord('0') || $codepoint > ord('9')) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private static function checkSequenceForSmallCleanEnergy(string $sequence): bool
+ {
$first = mb_substr($sequence, 0, 1);
if (! in_array($first, self::CLEAN_ENERGY_FIRST_LETTERS)) {
@@ -276,14 +312,40 @@ final readonly class RegistrationNumber
return strlen($this->sequence) === 6;
}
- public function isBatteryElectric(): bool
+ public function isSmallCleanEnergy(): bool
+ {
+ if (! $this->isCleanEnergy()) {
+ return false;
+ }
+
+ $first = mb_substr($this->sequence, 0, 1);
+
+ return in_array($first, self::CLEAN_ENERGY_FIRST_LETTERS, strict: true);
+ }
+
+ public function isLargeCleanEnergy(): bool
{
if (! $this->isCleanEnergy()) {
return false;
}
- $code = mb_substr($this->sequence, 0, 1);
+ $last = mb_substr($this->sequence, -1);
+
+ return in_array($last, self::CLEAN_ENERGY_FIRST_LETTERS, strict: true);
+ }
+
+ public function isBatteryElectric(): bool
+ {
+ $letter = match (true) {
+ $this->isSmallCleanEnergy() => mb_substr($this->sequence, 0, 1),
+ $this->isLargeCleanEnergy() => mb_substr($this->sequence, -1),
+ default => false,
+ };
+
+ if ($letter === false) {
+ return false;
+ }
- return in_array($code, self::BATTERY_ELECTRIC_LETTERS);
+ return in_array($letter, self::BATTERY_ELECTRIC_LETTERS, strict: true);
}
}
diff --git a/tests/RegistrationNumberTest.php b/tests/RegistrationNumberTest.php
index fcf5f33..5eb9f28 100644
--- a/tests/RegistrationNumberTest.php
+++ b/tests/RegistrationNumberTest.php
@@ -15,6 +15,7 @@ final class RegistrationNumberTest extends TestCase
{
#[DataProvider('provide_valid_registration_numbers')]
#[DataProvider('provide_valid_clean_energy_registration_numbers')]
+ #[DataProvider('provide_valid_large_clean_energy_vehicle_registration_numbers')]
public function test_valid_registration_number(string $registrationNumber): void
{
$instance = RegistrationNumber::make($registrationNumber);
@@ -23,6 +24,7 @@ final class RegistrationNumberTest extends TestCase
#[DataProvider('provide_invalid_registration_numbers')]
#[DataProvider('provide_invalid_clean_energy_registration_numbers')]
+ #[DataProvider('provide_invalid_large_clean_energy_vehicle_registration_numbers')]
public function test_invalid_registration_number(string $registrationNumber): void
{
$this->expectException(RegistrationNumberException::class);
@@ -36,13 +38,14 @@ final class RegistrationNumberTest extends TestCase
$this->assertFalse(RegistrationNumber::make('粤ED1234')->isCleanEnergy());
}
- public function test_is_battery_electric_determines_if_vehicle_is_a_fully_electric_vehicle(): void
+ public function test_is_battery_electric_determines_if_small_vehicle_is_a_fully_electric_vehicle(): void
{
$this->assertTrue(RegistrationNumber::make('粤ED12345')->isBatteryElectric());
$this->assertTrue(RegistrationNumber::make('粤EA12345')->isBatteryElectric());
$this->assertTrue(RegistrationNumber::make('粤EB12345')->isBatteryElectric());
$this->assertTrue(RegistrationNumber::make('粤EC12345')->isBatteryElectric());
$this->assertTrue(RegistrationNumber::make('粤EE12345')->isBatteryElectric());
+
$this->assertFalse(RegistrationNumber::make('粤EF12345')->isBatteryElectric());
$this->assertFalse(RegistrationNumber::make('粤EG12345')->isBatteryElectric());
$this->assertFalse(RegistrationNumber::make('粤EH12345')->isBatteryElectric());
@@ -50,6 +53,59 @@ final class RegistrationNumberTest extends TestCase
$this->assertFalse(RegistrationNumber::make('粤EK12345')->isBatteryElectric());
}
+ public function test_is_battery_electric_determines_if_large_vehicle_is_a_fully_electric_vehicle(): void
+ {
+ $this->assertTrue(RegistrationNumber::make('粤E12345D')->isBatteryElectric());
+ $this->assertTrue(RegistrationNumber::make('粤E12345A')->isBatteryElectric());
+ $this->assertTrue(RegistrationNumber::make('粤E12345B')->isBatteryElectric());
+ $this->assertTrue(RegistrationNumber::make('粤E12345C')->isBatteryElectric());
+ $this->assertTrue(RegistrationNumber::make('粤E12345E')->isBatteryElectric());
+
+ $this->assertFalse(RegistrationNumber::make('粤E12345F')->isBatteryElectric());
+ $this->assertFalse(RegistrationNumber::make('粤E12345G')->isBatteryElectric());
+ $this->assertFalse(RegistrationNumber::make('粤E12345H')->isBatteryElectric());
+ $this->assertFalse(RegistrationNumber::make('粤E12345J')->isBatteryElectric());
+ $this->assertFalse(RegistrationNumber::make('粤E12345K')->isBatteryElectric());
+ }
+
+ public function test_is_small_clean_energy_determines_if_vehicle_is_small_vehicle_with_clean_energy(): void
+ {
+ $this->assertTrue(RegistrationNumber::make('粤ED12345')->isSmallCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤EA12345')->isSmallCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤EB12345')->isSmallCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤EC12345')->isSmallCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤EE12345')->isSmallCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤EF12345')->isSmallCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤EG12345')->isSmallCleanEnergy());
+
+ $this->assertFalse(RegistrationNumber::make('粤E12345D')->isSmallCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤E12345A')->isSmallCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤E12345B')->isSmallCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤E12345C')->isSmallCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤E12345E')->isSmallCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤E12345F')->isSmallCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤E12345G')->isSmallCleanEnergy());
+ }
+
+ public function test_is_large_clean_energy_determines_if_vehicle_is_large_vehicle_with_clean_energy(): void
+ {
+ $this->assertTrue(RegistrationNumber::make('粤E12345D')->isLargeCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤E12345A')->isLargeCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤E12345B')->isLargeCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤E12345C')->isLargeCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤E12345E')->isLargeCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤E12345F')->isLargeCleanEnergy());
+ $this->assertTrue(RegistrationNumber::make('粤E12345G')->isLargeCleanEnergy());
+
+ $this->assertFalse(RegistrationNumber::make('粤ED12345')->isLargeCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤EA12345')->isLargeCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤EB12345')->isLargeCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤EC12345')->isLargeCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤EE12345')->isLargeCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤EF12345')->isLargeCleanEnergy());
+ $this->assertFalse(RegistrationNumber::make('粤EG12345')->isLargeCleanEnergy());
+ }
+
/**
* @return string[]
*/
@@ -86,7 +142,7 @@ final class RegistrationNumberTest extends TestCase
}
/**
- * @return string[]
+ * @return string[][]
*/
public static function provide_valid_clean_energy_registration_numbers(): array
{
@@ -106,6 +162,28 @@ final class RegistrationNumberTest extends TestCase
}
/**
+ * @return string[][]
+ */
+ public static function provide_valid_large_clean_energy_vehicle_registration_numbers(): array
+ {
+ return [
+ // Battery electric vehicle
+ ['粤E12345D'],
+ ['粤E12345A'],
+ ['粤E12345B'],
+ ['粤E12345C'],
+ ['粤E12345E'],
+
+ // Non-battery electric vehicle
+ ['粤E12345F'],
+ ['粤E12345G'],
+ ['粤E12345H'],
+ ['粤E12345J'],
+ ['粤E12345K'],
+ ];
+ }
+
+ /**
* @return string[]
*/
public static function provide_invalid_registration_numbers(): array
@@ -158,4 +236,18 @@ final class RegistrationNumberTest extends TestCase
['粤EDI1234'],
];
}
+
+ /**
+ * @return string[][]
+ */
+ public static function provide_invalid_large_clean_energy_vehicle_registration_numbers(): array
+ {
+ return [
+ ['粤E1234DD'],
+ ['粤E123D4D'],
+ ['粤E12D34D'],
+ ['粤E1D234D'],
+ ['粤ED1234D'],
+ ];
+ }
}