Skip to content

Instantly share code, notes, and snippets.

@jiromm
Last active March 31, 2020 11:21
Show Gist options
  • Save jiromm/ba332a06d38fd621e54cc3735a90845c to your computer and use it in GitHub Desktop.
Save jiromm/ba332a06d38fd621e54cc3735a90845c to your computer and use it in GitHub Desktop.
wget -O phpunit https://phar.phpunit.de/phpunit-9.phar && php phpunit UnitTest.php
<?php
function getNext(
int $alphaCount = 1,
int $minNumberCount = 0,
array $skippableAlpha = [],
array $skippableNumbers = [],
string $unitNumber = null): string {
if ($alphaCount < 1 || $minNumberCount < 0) throw new \Exception('Empty values');
$skippableAlpha = array_map('strtoupper', $skippableAlpha);
asort($skippableAlpha);
if ($skippableAlpha == range('A', 'Z')) throw new \Exception('All alphabets are used');
foreach ($skippableAlpha as $alpha) {
$alphaCode = ord($alpha);
if (mb_strlen($alpha) > 1) throw new \Exception('Wrong character length for skippable alphas');
if ($alphaCode < 65 || $alphaCode > 90) throw new \Exception('Wrong character for skippable alphas');
}
asort($skippableNumbers);
if ($skippableNumbers == range(0, 9)) throw new \Exception('All digits are used');
foreach ($skippableNumbers as $num) {
if (!ctype_digit((string)$num)) throw new \Exception('Skippable numbers are not numbers');
if ($num < 0 || $num > 9) throw new \Exception('Wrong character length for skippable numbers');
}
if ($unitNumber === '') throw new \Exception('Unit number cannot be empty. Should be null or real unit number');
if ($minNumberCount === 0) {
$minNumberCount = 1;
}
// Not most effective way to define default unit number in case it missed
// But this way code is flat and much readable
$fromScratch = false;
if ($unitNumber === null) {
$code = str_repeat('A', $alphaCount);
$number = str_repeat('0', $minNumberCount);
$unitNumber = $code . $number;
$fromScratch = true;
}
$splitUnit = function (string $unit) {
if (!preg_match('/^([A-Z]+)(\d+)$/', $unit, $matches)) {
throw new Exception('Given unit number format is wrong');
}
if (count($matches) !== 3) throw new \RuntimeException('Something went wrong with unit number decode');
array_shift($matches);
return $matches;
};
[$code, $number] = $splitUnit($unitNumber);
$codeLen = strlen($code);
$numberLen = strlen($number);
if ($codeLen > $alphaCount) throw new \Exception('Given unit number\'s alpha number length cannot be less than requested');
if ($codeLen < $alphaCount) {
$code = str_repeat('A', $alphaCount);
$number = str_repeat('0', $minNumberCount);
$unitNumber = $code . $number;
} else {
if (!$fromScratch) {
[$codeOld] = $splitUnit($unitNumber);
[$code] = $splitUnit(++$unitNumber);
if ($codeOld !== $code) {
$number = str_repeat('0', $numberLen);
$unitNumber = $code . $number;
}
}
}
// Convert to string to apply in_array function
foreach ($skippableNumbers as $i => $number) {
$skippableNumbers[$i] = (string)$number;
}
$isValid = function (string $unit) use ($skippableAlpha, $skippableNumbers) {
foreach (str_split($unit) as $char) {
if (in_array($char, $skippableAlpha) || in_array($char, $skippableNumbers)) {
return false;
}
}
return true;
};
while (!$isValid($unitNumber)) {
if (strlen($code) > $alphaCount) {
$numberLen++;
$code = str_repeat('A', $alphaCount);
$number = str_repeat('0', $numberLen);
$unitNumber = $code . $number;
} else {
[$codeOld] = $splitUnit($unitNumber);
$unitNumber++;
[$code] = $splitUnit($unitNumber);
if ($codeOld !== $code) {
$number = str_repeat('0', $numberLen);
$unitNumber = $code . $number;
}
}
}
return $unitNumber;
}
<?php
use PHPUnit\Framework\TestCase;
include 'get_next.php';
final class UnitTest extends TestCase
{
/**
* @dataProvider invalidDataProvider
*/
public function testEmptyValues($alpha, $num = 0, $eAlpha = [], $eNum = [], $unit = null)
{
$this->expectException(\Throwable::class);
getNext($alpha, $num, $eAlpha, $eNum, $unit);
}
public function invalidDataProvider()
{
return [
[0],
[-1],
[-5021625],
[1, -1],
[1, 2, [1]],
[1, 2, ['AA']],
[1, 2, ['Ա']],
[1, 2, ['A', 2]],
[1, 2, ['A', 'B', 'C', 'D', '$', 'E']],
[1, 2, range('A', 'Z')],
[1, 2, [], ['A']],
[1, 2, [], [-1]],
[1, 2, [], [11]],
[1, 2, [], ['A', 1]],
[1, 2, [], [1, 2, 'a', 3]],
[1, 2, [], [1, 2, '%', 3]],
[1, 2, [], [-1]],
[1, 2, [], [1, -1, 3]],
[1, 2, [], range(0, 9)],
[1, 2, [], [], '$'],
[1, 2, [], [], 'A$'],
[1, 2, [], [], 'A1$'],
[1, 2, [], [], 'A1$1'],
[1, 2, [], [], '1'],
[1, 2, [], [], '1A'],
[2, 2, [], [], 'XYZ00'],
[1, 2, [], [], ''],
];
}
/**
* @dataProvider validDataProvider
*/
public function testValidValues($alpha, $num, $eAlpha, $eNum, $unit, $returnedResult)
{
$result = getNext($alpha, $num, $eAlpha, $eNum, $unit);
$this->assertEquals($result, $returnedResult);
}
public function validDataProvider()
{
return [
[1, 0, [], [], null, 'A0'],
[1, 5, [], [], null, 'A00000'],
[2, 30, [], [], null, 'AA' . str_repeat('0', 30)],
[2, 2, [], [], 'AB233', 'AB234'],
[2, 2, [], [], 'AZ999', 'BA000'],
[2, 2, [], [], 'A456', 'AA00'],
[2, 2, ['A'], [], 'AC123', 'BB000'],
[2, 2, ['A', 'B'], [], 'AC123', 'CC000'],
[1, 0, [], [0], null, 'A1'],
[1, 0, [], [0, 1], null, 'A2'],
[1, 0, [], [0], 'Z9', 'A11'],
[2, 2, ['A', 'B'], [0, 1], 'AC123', 'CC222'],
[3, 2, ['A', 'B', 'C', 'D', 'E', 'F'], [0, 1, 2, 3, 4, 5], 'A1', 'GGG6'],
[2, 2, ['Z'], [0, 9], 'YY889', 'AA1111'],
];
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment