Skip to content

Commit

Permalink
Added Finnish personal identity code rule and tests.
Browse files Browse the repository at this point in the history
  • Loading branch information
vhuk committed Mar 12, 2024
1 parent 52b75bc commit 35d8d2e
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 0 deletions.
69 changes: 69 additions & 0 deletions library/Rules/Hetu.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

/*
* Copyright (c) Ville Hukkamäki <[email protected]>
* SPDX-License-Identifier: MIT
*/

declare(strict_types=1);

namespace Respect\Validation\Rules;

use Respect\Validation\Message\Template;
use Respect\Validation\Rules\Core\Simple;

use function is_string;
use function preg_match;
use function strtoupper;

/**
* @see https://en.wikipedia.org/wiki/National_identification_number#Finland
*/
#[Template(
'{{name}} must be a valid Finnish personal identity code',
'{{name}} must not be a valid Finnish personal identity code',
)]
final class Hetu extends Simple
{
public function validate(mixed $input): bool
{
if (!is_string($input)) {
return false;
}

$input = strtoupper($input);

if (!preg_match('/^(\d{2})(\d{2})(\d{2})([+\-A-FU-Y])(\d{3})([0-9A-FHJ-NPR-Y])$/', $input, $m)) {
return false;
}

$century = match ($m[4]) {
'+' => '18',
'-','U','V','W','X','Y' => '19',
'A','B','C','D','E','F' => '20',
default => null,
};

if ($century === null) {
return false;

Check warning on line 48 in library/Rules/Hetu.php

View check run for this annotation

Codecov / codecov/patch

library/Rules/Hetu.php#L48

Added line #L48 was not covered by tests
}

$dateRule = new Date();
if (!$dateRule->evaluate($century . $m[3] . '-' . $m[2] . '-' . $m[1])->isValid) {
return false;
}

return $this->getChecksum($m[1] . $m[2] . $m[3] . $m[5]) === $m[6];
}

private function getChecksum(string $s): string
{
$mod = (int)$s % 31;
$tab = [
'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F','H','J','K','L','M','N','P',
'R','S','T','U','C','W','X','Y',
];

return $tab[$mod];
}
}
66 changes: 66 additions & 0 deletions tests/unit/Rules/HetuTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

/*
* Copyright (c) Ville Hukkamäki <[email protected]>
* SPDX-License-Identifier: MIT
*/

declare(strict_types=1);

namespace Respect\Validation\Rules;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\Group;
use Respect\Validation\Test\RuleTestCase;

#[Group('rule')]
#[CoversClass(Hetu::class)]
final class HetuTest extends RuleTestCase
{
/** @return iterable<array{Hetu, mixed}> */
public static function providerForValidInput(): iterable
{
$rule = new Hetu();

return [
[$rule, '010106A9012'],
[$rule, '290199-907A'],
[$rule, '010199+9012'],
[$rule, '280291+913L'],
[$rule, '280291+923X'],
];
}

/** @return iterable<array{Hetu, mixed}> */
public static function providerForInvalidInput(): iterable
{
$rule = new Hetu();

return [
[$rule, '010106_9012'],
[$rule, '010106G9012'],
[$rule, '010106Z9012'],
[$rule, '010106A901G'],
[$rule, '010106A901I'],
[$rule, '010106A901O'],
[$rule, '010106A901Q'],
[$rule, '010106A901Z'],
[$rule, '010106!9012'],
[$rule, '010106'],
[$rule, '01X199+9012'],
[$rule, '01X199Z9012'],
[$rule, '01X199T9012'],
[$rule, '999999A9999'],
[$rule, '999999A999F'],
[$rule, '300201A1236'],
[$rule, '290201A123J'],

[$rule, null],
[$rule, []],
[$rule, false],
[$rule, 42],
[$rule, '127.0.0.1'],
[$rule, new DateTime()],
];
}
}

0 comments on commit 35d8d2e

Please sign in to comment.