Merge branch 'development' into feature/TTD-2140/DB-IO-SQLite

This commit is contained in:
Clemens Schwaighofer
2025-06-05 18:26:31 +09:00
32 changed files with 4348 additions and 320 deletions

View File

@@ -1,5 +1,6 @@
base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/";
base=$(pwd)"/";
# must be run in ${base}
cd $base || exit;
${base}tools/phan --progress-bar -C --analyze-twice;
#PHAN_DISABLE_XDEBUG_WARN=1;${base}tools/phan --progress-bar -C --analyze-twice
PHAN_DISABLE_XDEBUG_WARN=1;${base}vendor/bin/phan --progress-bar -C --analyze-twice
cd ~ || exit;

View File

@@ -1,4 +1,4 @@
base="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/";
base=$(pwd)"/";
# must be run in ${base}
cd $base || exit;
${base}tools/phpstan;

View File

@@ -23,7 +23,7 @@ EOF
}
# set base variables
BASE_PATH="/storage/var/www/html/developers/clemens/core_data/php_libraries/trunk/";
BASE_PATH=$(pwd)"/";
PHPUNIT_CONFIG="${BASE_PATH}phpunit.xml";
PHP_BIN_PATH=$(which php);
if [ -z "${PHP_BIN_PATH}" ]; then

View File

@@ -0,0 +1,404 @@
<?php
// This code was created by Claude Sonnet 4
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Combined\ArrayHandler;
class CoreLibsCombinedArrayHandlerFindArraysMissingKeyTest extends TestCase
{
private const DATA_SEPARATOR = ':'; // Updated to match your class's separator
/**
* Test finding missing single key when searching by value without specific key
*/
public function testFindMissingSingleKeyWithValueSearch()
{
$array = [
'item1' => [
'name' => 'John',
'age' => 25
// missing 'email' key
],
'item2' => [
'name' => 'Jane',
'age' => 30,
'email' => 'jane@example.com'
],
'item3' => [
'name' => 'John', // same value as item1
'age' => 35,
'email' => 'john2@example.com'
]
];
$result = ArrayHandler::findArraysMissingKey($array, 'John', 'email');
$this->assertCount(1, $result);
$this->assertEquals($array['item1'], $result[0]['content']);
$this->assertEquals('item1', $result[0]['path']);
$this->assertEquals(['email'], $result[0]['missing_key']);
}
/**
* Test finding missing single key when searching by specific key-value pair
*/
public function testFindMissingSingleKeyWithKeyValueSearch()
{
$array = [
'user1' => [
'id' => 1,
'name' => 'Alice'
// missing 'status' key
],
'user2' => [
'id' => 2,
'name' => 'Bob',
'status' => 'active'
],
'user3' => [
'id' => 1, // same id as user1
'name' => 'Charlie',
'status' => 'inactive'
]
];
$result = ArrayHandler::findArraysMissingKey($array, 1, 'status', 'id');
$this->assertCount(1, $result);
$this->assertEquals($array['user1'], $result[0]['content']);
$this->assertEquals('user1', $result[0]['path']);
$this->assertEquals(['status'], $result[0]['missing_key']);
}
/**
* Test finding missing multiple keys
*/
public function testFindMissingMultipleKeys()
{
$array = [
'record1' => [
'name' => 'Test',
'value' => 100
// missing both 'date' and 'status' keys
],
'record2' => [
'name' => 'Test',
'value' => 200,
'date' => '2023-01-01'
// missing 'status' key
],
'record3' => [
'name' => 'Test',
'value' => 300,
'date' => '2023-01-02',
'status' => 'complete'
]
];
$result = ArrayHandler::findArraysMissingKey($array, 'Test', ['date', 'status']);
$this->assertCount(2, $result);
// First result should be record1 missing both keys
$this->assertEquals($array['record1'], $result[0]['content']);
$this->assertEquals('record1', $result[0]['path']);
$this->assertContains('date', $result[0]['missing_key']);
$this->assertContains('status', $result[0]['missing_key']);
$this->assertCount(2, $result[0]['missing_key']);
// Second result should be record2 missing status key
$this->assertEquals($array['record2'], $result[1]['content']);
$this->assertEquals('record2', $result[1]['path']);
$this->assertEquals(['status'], $result[1]['missing_key']);
}
/**
* Test with nested arrays
*/
public function testFindMissingKeyInNestedArrays()
{
$array = [
'section1' => [
'items' => [
'item1' => [
'name' => 'Product A',
'price' => 99.99
// missing 'category' key
],
'item2' => [
'name' => 'Product B',
'price' => 149.99,
'category' => 'electronics'
]
]
],
'section2' => [
'data' => [
'name' => 'Product A', // same name as nested item
'category' => 'books'
]
]
];
$result = ArrayHandler::findArraysMissingKey($array, 'Product A', 'category');
$this->assertCount(1, $result);
$this->assertEquals($array['section1']['items']['item1'], $result[0]['content']);
$this->assertEquals('section1:items:item1', $result[0]['path']);
$this->assertEquals(['category'], $result[0]['missing_key']);
}
/**
* Test when no arrays are missing the required key
*/
public function testNoMissingKeys()
{
$array = [
'item1' => [
'name' => 'John',
'email' => 'john@example.com'
],
'item2' => [
'name' => 'Jane',
'email' => 'jane@example.com'
]
];
$result = ArrayHandler::findArraysMissingKey($array, 'John', 'email');
$this->assertEmpty($result);
}
/**
* Test when search value is not found in any array
*/
public function testSearchValueNotFound()
{
$array = [
'item1' => [
'name' => 'John',
'age' => 25
],
'item2' => [
'name' => 'Jane',
'age' => 30
]
];
$result = ArrayHandler::findArraysMissingKey($array, 'Bob', 'email');
$this->assertEmpty($result);
}
/**
* Test with different data types for search value
*/
public function testDifferentSearchValueTypes()
{
$array = [
'item1' => [
'active' => true,
'count' => 5
// missing 'label' key
],
'item2' => [
'active' => false,
'count' => 10,
'label' => 'test'
],
'item3' => [
'active' => true, // same boolean as item1
'count' => 15,
'label' => 'another'
]
];
// Test with boolean
$result = ArrayHandler::findArraysMissingKey($array, true, 'label', 'active');
$this->assertCount(1, $result);
$this->assertEquals('item1', $result[0]['path']);
// Test with integer
$result = ArrayHandler::findArraysMissingKey($array, 5, 'label', 'count');
$this->assertCount(1, $result);
$this->assertEquals('item1', $result[0]['path']);
}
/**
* Test with empty array
*/
public function testEmptyArray()
{
$array = [];
$result = ArrayHandler::findArraysMissingKey($array, 'test', 'key');
$this->assertEmpty($result);
}
/**
* Test with array containing non-array values
*/
public function testMixedArrayTypes()
{
$array = [
'string_value' => 'hello',
'numeric_value' => 123,
'array_value' => [
'name' => 'test',
// missing 'type' key
],
'another_array' => [
'name' => 'test',
'type' => 'example'
]
];
$result = ArrayHandler::findArraysMissingKey($array, 'test', 'type');
$this->assertCount(1, $result);
$this->assertEquals($array['array_value'], $result[0]['content']);
$this->assertEquals('array_value', $result[0]['path']);
$this->assertEquals(['type'], $result[0]['missing_key']);
}
/**
* Test path building with deeper nesting
*/
public function testDeepNestingPathBuilding()
{
$array = [
'level1' => [
'level2' => [
'level3' => [
'items' => [
'target_item' => [
'name' => 'deep_test',
// missing 'required_field'
]
]
]
]
]
];
$result = ArrayHandler::findArraysMissingKey($array, 'deep_test', 'required_field');
$this->assertCount(1, $result);
$this->assertEquals('level1:level2:level3:items:target_item', $result[0]['path']);
}
/**
* Test with custom path separator
*/
public function testCustomPathSeparator()
{
$array = [
'level1' => [
'level2' => [
'item' => [
'name' => 'test',
// missing 'type' key
]
]
]
];
$result = ArrayHandler::findArraysMissingKey($array, 'test', 'type', null, '/');
$this->assertCount(1, $result);
$this->assertEquals('level1/level2/item', $result[0]['path']);
}
/**
* Test default path separator behavior
*/
public function testDefaultPathSeparator()
{
$array = [
'parent' => [
'child' => [
'name' => 'test',
// missing 'value' key
]
]
];
// Using default separator (should be ':')
$result = ArrayHandler::findArraysMissingKey($array, 'test', 'value');
$this->assertCount(1, $result);
$this->assertEquals('parent:child', $result[0]['path']);
}
/**
* Test different path separators don't affect search logic
*/
public function testPathSeparatorDoesNotAffectSearchLogic()
{
$array = [
'section' => [
'data' => [
'id' => 123,
'name' => 'item'
// missing 'status'
]
]
];
// Test with different separators - results should be identical except for path
$result1 = ArrayHandler::findArraysMissingKey($array, 123, 'status', 'id', ':');
$result2 = ArrayHandler::findArraysMissingKey($array, 123, 'status', 'id', '.');
$result3 = ArrayHandler::findArraysMissingKey($array, 123, 'status', 'id', '/');
$this->assertCount(1, $result1);
$this->assertCount(1, $result2);
$this->assertCount(1, $result3);
// Content and missing_key should be the same
$this->assertEquals($result1[0]['content'], $result2[0]['content']);
$this->assertEquals($result1[0]['content'], $result3[0]['content']);
$this->assertEquals($result1[0]['missing_key'], $result2[0]['missing_key']);
$this->assertEquals($result1[0]['missing_key'], $result3[0]['missing_key']);
// Paths should be different based on separator
$this->assertEquals('section:data', $result1[0]['path']);
$this->assertEquals('section.data', $result2[0]['path']);
$this->assertEquals('section/data', $result3[0]['path']);
}
/**
* test type checking
*/
public function testStrictTypeChecking()
{
$array = [
'item1' => [
'id' => '123', // string
'name' => 'test'
// missing 'status'
],
'item2' => [
'id' => 123, // integer
'name' => 'test2',
'status' => 'active'
]
];
// Search for integer 123 - should only match item2
$result = ArrayHandler::findArraysMissingKey($array, 123, 'status', 'id');
$this->assertEmpty($result); // item2 has the status key
// Search for string '123' - should only match item1
$result = ArrayHandler::findArraysMissingKey($array, '123', 'status', 'id');
$this->assertCount(1, $result);
$this->assertEquals('item1', $result[0]['path']);
}
}
// __END__

View File

@@ -0,0 +1,333 @@
<?php
// This code was created by Claude Sonnet 4
// modification for value checks with assertEqualsCanonicalizing
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Combined\ArrayHandler;
class CoreLibsCombinedArrayHandlerKsortArrayTest extends TestCase
{
/**
* Test basic ascending sort (default behavior)
*/
public function testKsortArrayBasicAscending(): void
{
$input = [
'zebra' => 'value1',
'apple' => 'value2',
'banana' => 'value3',
'cherry' => 'value4'
];
$expected = [
'apple' => 'value2',
'banana' => 'value3',
'cherry' => 'value4',
'zebra' => 'value1'
];
$result = ArrayHandler::ksortArray($input);
$this->assertEquals($expected, $result);
$this->assertEquals(array_keys($expected), array_keys($result));
}
/**
* Test descending sort with reverse=true
*/
public function testKsortArrayDescending(): void
{
$input = [
'zebra' => 'value1',
'apple' => 'value2',
'banana' => 'value3',
'cherry' => 'value4'
];
$expected = [
'zebra' => 'value1',
'cherry' => 'value4',
'banana' => 'value3',
'apple' => 'value2'
];
$result = ArrayHandler::ksortArray($input, false, true);
$this->assertEquals($expected, $result);
$this->assertEquals(array_keys($expected), array_keys($result));
}
/**
* Test case-insensitive ascending sort
*/
public function testKsortArrayCaseInsensitiveAscending(): void
{
$input = [
'Zebra' => 'value1',
'apple' => 'value2',
'Banana' => 'value3',
'cherry' => 'value4'
];
$expected = [
'apple' => 'value2',
'Banana' => 'value3',
'cherry' => 'value4',
'Zebra' => 'value1'
];
$result = ArrayHandler::ksortArray($input, true);
$this->assertEquals($expected, $result);
$this->assertEquals(array_keys($expected), array_keys($result));
}
/**
* Test case-insensitive descending sort
*/
public function testKsortArrayCaseInsensitiveDescending(): void
{
$input = [
'Zebra' => 'value1',
'apple' => 'value2',
'Banana' => 'value3',
'cherry' => 'value4'
];
$expected = [
'Zebra' => 'value1',
'cherry' => 'value4',
'Banana' => 'value3',
'apple' => 'value2'
];
$result = ArrayHandler::ksortArray($input, true, true);
$this->assertEquals($expected, $result);
$this->assertEquals(array_keys($expected), array_keys($result));
}
/**
* Test with mixed case keys to verify case sensitivity behavior
*/
public function testKsortArrayCaseSensitivityComparison(): void
{
$input = [
'B' => 'value1',
'a' => 'value2',
'C' => 'value3',
'b' => 'value4'
];
// Case-sensitive sort (uppercase comes before lowercase in ASCII)
$expectedCaseSensitive = [
'B' => 'value1',
'C' => 'value3',
'a' => 'value2',
'b' => 'value4'
];
// Case-insensitive sort
$expectedCaseInsensitive = [
'a' => 'value2',
'B' => 'value1',
'b' => 'value4',
'C' => 'value3'
];
$resultCaseSensitive = ArrayHandler::ksortArray($input, false);
$resultCaseInsensitive = ArrayHandler::ksortArray($input, true);
$this->assertEquals($expectedCaseSensitive, $resultCaseSensitive);
$this->assertEquals($expectedCaseInsensitive, $resultCaseInsensitive);
}
/**
* Test with numeric string keys
*/
public function testKsortArrayNumericStringKeys(): void
{
$input = [
'10' => 'value1',
'2' => 'value2',
'1' => 'value3',
'20' => 'value4'
];
// String comparison, not numeric
$expected = [
'1' => 'value3',
'10' => 'value1',
'2' => 'value2',
'20' => 'value4'
];
$result = ArrayHandler::ksortArray($input);
$this->assertEquals($expected, $result);
}
/**
* Test with special characters in keys
*/
public function testKsortArraySpecialCharacters(): void
{
$input = [
'key_with_underscore' => 'value1',
'key-with-dash' => 'value2',
'key.with.dot' => 'value3',
'key with space' => 'value4',
'keyWithCamelCase' => 'value5'
];
$result = ArrayHandler::ksortArray($input);
// Verify it doesn't throw an error and maintains all keys
$this->assertCount(5, $result);
$this->assertArrayHasKey('key_with_underscore', $result);
$this->assertArrayHasKey('key-with-dash', $result);
$this->assertArrayHasKey('key.with.dot', $result);
$this->assertArrayHasKey('key with space', $result);
$this->assertArrayHasKey('keyWithCamelCase', $result);
}
/**
* Test with empty array
*/
public function testKsortArrayEmpty(): void
{
$input = [];
$result = ArrayHandler::ksortArray($input);
$this->assertEquals([], $result);
$this->assertIsArray($result);
}
/**
* Test with single element array
*/
public function testKsortArraySingleElement(): void
{
$input = ['onlykey' => 'onlyvalue'];
$result = ArrayHandler::ksortArray($input);
$this->assertEquals($input, $result);
}
/**
* Test that original array is not modified (function returns new array)
*/
public function testKsortArrayDoesNotModifyOriginal(): void
{
$original = [
'zebra' => 'value1',
'apple' => 'value2',
'banana' => 'value3'
];
$originalCopy = $original; // Keep a copy for comparison
$result = ArrayHandler::ksortArray($original);
// Original array should remain unchanged
$this->assertEquals($originalCopy, $original);
$this->assertNotEquals(array_keys($original), array_keys($result));
}
/**
* Test with complex mixed data types as values
*/
public function testKsortArrayMixedValueTypes(): void
{
$input = [
'string_key' => 'string_value',
'array_key' => ['nested', 'array'],
'int_key' => 42,
'bool_key' => true,
'null_key' => null
];
$result = ArrayHandler::ksortArray($input);
// Check that all keys are preserved and sorted
$expectedKeys = ['array_key', 'bool_key', 'int_key', 'null_key', 'string_key'];
$this->assertEquals($expectedKeys, array_keys($result));
// Check that values are preserved correctly
$this->assertEquals('string_value', $result['string_key']);
$this->assertEquals(['nested', 'array'], $result['array_key']);
$this->assertEquals(42, $result['int_key']);
$this->assertTrue($result['bool_key']);
$this->assertNull($result['null_key']);
}
/**
* Test all parameter combinations
*/
public function testKsortArrayAllParameterCombinations(): void
{
$input = [
'Delta' => 'value1',
'alpha' => 'value2',
'Charlie' => 'value3',
'bravo' => 'value4'
];
// Test all 4 combinations
$result1 = ArrayHandler::ksortArray($input, false, false); // default
$result2 = ArrayHandler::ksortArray($input, false, true); // reverse only
$result3 = ArrayHandler::ksortArray($input, true, false); // lowercase only
$result4 = ArrayHandler::ksortArray($input, true, true); // both
// Each should produce different ordering
$this->assertNotEquals(array_keys($result1), array_keys($result2));
$this->assertNotEquals(array_keys($result1), array_keys($result3));
$this->assertNotEquals(array_keys($result1), array_keys($result4));
$this->assertNotEquals(array_keys($result2), array_keys($result3));
$this->assertNotEquals(array_keys($result2), array_keys($result4));
$this->assertNotEquals(array_keys($result3), array_keys($result4));
// But all should have same keys and values, just different order
$this->assertEqualsCanonicalizing(array_values($input), array_values($result1));
$this->assertEqualsCanonicalizing(array_values($input), array_values($result2));
$this->assertEqualsCanonicalizing(array_values($input), array_values($result3));
$this->assertEqualsCanonicalizing(array_values($input), array_values($result4));
}
/**
* Data provider for comprehensive testing
*/
public function sortingParametersProvider(): array
{
return [
'default' => [false, false],
'reverse' => [false, true],
'lowercase' => [true, false],
'lowercase_reverse' => [true, true],
];
}
/**
* Test that function works with all parameter combinations using data provider
*
* @dataProvider sortingParametersProvider
*/
public function testKsortArrayWithDataProvider(bool $lowerCase, bool $reverse): void
{
$input = [
'Zebra' => 'animal1',
'apple' => 'fruit1',
'Banana' => 'fruit2',
'cat' => 'animal2'
];
$result = ArrayHandler::ksortArray($input, $lowerCase, $reverse);
// Basic assertions that apply to all combinations
$this->assertIsArray($result);
$this->assertCount(4, $result);
$this->assertArrayHasKey('Zebra', $result);
$this->assertArrayHasKey('apple', $result);
$this->assertArrayHasKey('Banana', $result);
$this->assertArrayHasKey('cat', $result);
}
}
// __END__

View File

@@ -0,0 +1,383 @@
<?php
// created by Claude Sonnet 4
// testRecursiveSearchWithFlatResult had wrong retunr count
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Combined\ArrayHandler;
class CoreLibsCombinedArrayHandlerSelectArrayFromOptionTest extends TestCase
{
private array $testData;
private array $nestedTestData;
protected function setUp(): void
{
$this->testData = [
'item1' => [
'name' => 'John',
'age' => 25,
'status' => 'active',
'score' => 85.5
],
'item2' => [
'name' => 'jane',
'age' => 30,
'status' => 'inactive',
'score' => 92.0
],
'item3' => [
'name' => 'Bob',
'age' => 25,
'status' => 'active',
'score' => 78.3
],
'item4' => [
'name' => 'Alice',
'age' => 35,
'status' => 'pending',
'score' => 88.7
]
];
$this->nestedTestData = [
'level1_a' => [
'name' => 'Level1A',
'type' => 'parent',
'children' => [
'child1' => [
'name' => 'Child1',
'type' => 'child',
'active' => true
],
'child2' => [
'name' => 'Child2',
'type' => 'child',
'active' => false
]
]
],
'level1_b' => [
'name' => 'Level1B',
'type' => 'parent',
'children' => [
'child3' => [
'name' => 'Child3',
'type' => 'child',
'active' => true,
'nested' => [
'deep1' => [
'name' => 'Deep1',
'type' => 'deep',
'active' => true
]
]
]
]
],
'item5' => [
'name' => 'Direct',
'type' => 'child',
'active' => false
]
];
}
public function testEmptyArrayReturnsEmpty(): void
{
$result = ArrayHandler::selectArrayFromOption([], 'name', 'John');
$this->assertEmpty($result);
}
public function testBasicStringSearch(): void
{
$result = ArrayHandler::selectArrayFromOption($this->testData, 'name', 'John');
$this->assertCount(1, $result);
$this->assertArrayHasKey('item1', $result);
$this->assertEquals('John', $result['item1']['name']);
}
public function testBasicIntegerSearch(): void
{
$result = ArrayHandler::selectArrayFromOption($this->testData, 'age', 25);
$this->assertCount(2, $result);
$this->assertArrayHasKey('item1', $result);
$this->assertArrayHasKey('item3', $result);
}
public function testBasicFloatSearch(): void
{
$result = ArrayHandler::selectArrayFromOption($this->testData, 'score', 85.5);
$this->assertCount(1, $result);
$this->assertArrayHasKey('item1', $result);
$this->assertEquals(85.5, $result['item1']['score']);
}
public function testBasicBooleanSearch(): void
{
$data = [
'item1' => ['enabled' => true, 'name' => 'Test1'],
'item2' => ['enabled' => false, 'name' => 'Test2'],
'item3' => ['enabled' => true, 'name' => 'Test3']
];
$result = ArrayHandler::selectArrayFromOption($data, 'enabled', true);
$this->assertCount(2, $result);
$this->assertArrayHasKey('item1', $result);
$this->assertArrayHasKey('item3', $result);
}
public function testStrictComparison(): void
{
$data = [
'item1' => ['value' => '25', 'name' => 'String25'],
'item2' => ['value' => 25, 'name' => 'Int25'],
'item3' => ['value' => 25.0, 'name' => 'Float25']
];
// Non-strict should match all
$nonStrictResult = ArrayHandler::selectArrayFromOption($data, 'value', 25, false);
$this->assertCount(3, $nonStrictResult);
// Strict should only match exact type
$strictResult = ArrayHandler::selectArrayFromOption($data, 'value', 25, true);
$this->assertCount(1, $strictResult);
$this->assertArrayHasKey('item2', $strictResult);
}
public function testCaseInsensitiveSearch(): void
{
$result = ArrayHandler::selectArrayFromOption($this->testData, 'name', 'JANE', false, true);
$this->assertCount(1, $result);
$this->assertArrayHasKey('item2', $result);
$this->assertEquals('jane', $result['item2']['name']);
}
public function testCaseSensitiveSearch(): void
{
$result = ArrayHandler::selectArrayFromOption($this->testData, 'name', 'JANE', false, false);
$this->assertEmpty($result);
}
public function testRecursiveSearchWithFlatResult(): void
{
$result = ArrayHandler::selectArrayFromOption(
$this->nestedTestData,
'type',
'child',
false,
false,
true,
true,
':*'
);
$this->assertCount(4, $result);
$this->assertArrayHasKey('level1_a:*children:*child1', $result);
$this->assertArrayHasKey('level1_a:*children:*child2', $result);
$this->assertArrayHasKey('level1_b:*children:*child3', $result);
$this->assertArrayHasKey('item5', $result);
}
public function testRecursiveSearchWithNestedResult(): void
{
$result = ArrayHandler::selectArrayFromOption(
$this->nestedTestData,
'type',
'child',
false,
false,
true,
false
);
$this->assertCount(3, $result);
$this->assertArrayHasKey('level1_a', $result);
$this->assertArrayHasKey('level1_b', $result);
$this->assertArrayHasKey('item5', $result);
// Check nested structure is preserved
$this->assertArrayHasKey('children', $result['level1_a']);
$this->assertArrayHasKey('child1', $result['level1_a']['children']);
$this->assertArrayHasKey('child2', $result['level1_a']['children']);
}
public function testRecursiveSearchDeepNesting(): void
{
$result = ArrayHandler::selectArrayFromOption(
$this->nestedTestData,
'type',
'deep',
false,
false,
true,
true,
':*'
);
$this->assertCount(1, $result);
$this->assertArrayHasKey('level1_b:*children:*child3:*nested:*deep1', $result);
$this->assertEquals('Deep1', $result['level1_b:*children:*child3:*nested:*deep1']['name']);
}
public function testCustomFlatSeparator(): void
{
$result = ArrayHandler::selectArrayFromOption(
$this->nestedTestData,
'type',
'child',
false,
false,
true,
true,
'|'
);
$this->assertArrayHasKey('level1_a|children|child1', $result);
$this->assertArrayHasKey('level1_a|children|child2', $result);
$this->assertArrayHasKey('level1_b|children|child3', $result);
}
public function testNonRecursiveSearch(): void
{
$result = ArrayHandler::selectArrayFromOption(
$this->nestedTestData,
'type',
'child',
false,
false,
false
);
// Should only find direct matches, not nested ones
$this->assertCount(1, $result);
$this->assertArrayHasKey('item5', $result);
}
public function testNoMatchesFound(): void
{
$result = ArrayHandler::selectArrayFromOption($this->testData, 'name', 'NonExistent');
$this->assertEmpty($result);
}
public function testMissingLookupKey(): void
{
$result = ArrayHandler::selectArrayFromOption($this->testData, 'nonexistent_key', 'value');
$this->assertEmpty($result);
}
public function testCombinedStrictAndCaseInsensitive(): void
{
$data = [
'item1' => ['name' => 'Test', 'id' => '123'],
'item2' => ['name' => 'test', 'id' => 123],
'item3' => ['name' => 'TEST', 'id' => '123']
];
// Case insensitive but strict type matching
$result = ArrayHandler::selectArrayFromOption($data, 'id', '123', true, true);
$this->assertCount(2, $result);
$this->assertArrayHasKey('item1', $result);
$this->assertArrayHasKey('item3', $result);
}
public function testBooleanWithCaseInsensitive(): void
{
$data = [
'item1' => ['active' => true, 'name' => 'Test1'],
'item2' => ['active' => false, 'name' => 'Test2']
];
// Case insensitive flag should not affect boolean comparison
$result = ArrayHandler::selectArrayFromOption($data, 'active', true, false, true);
$this->assertCount(1, $result);
$this->assertArrayHasKey('item1', $result);
}
public function testArrayWithNumericKeys(): void
{
$data = [
0 => ['name' => 'First', 'type' => 'test'],
1 => ['name' => 'Second', 'type' => 'test'],
2 => ['name' => 'Third', 'type' => 'other']
];
$result = ArrayHandler::selectArrayFromOption($data, 'type', 'test');
$this->assertCount(2, $result);
$this->assertArrayHasKey(0, $result);
$this->assertArrayHasKey(1, $result);
}
public function testRecursiveWithMixedKeyTypes(): void
{
$data = [
'string_key' => [
'name' => 'Parent',
'type' => 'parent',
0 => [
'name' => 'Child0',
'type' => 'child'
],
'child_key' => [
'name' => 'ChildKey',
'type' => 'child'
]
]
];
$result = ArrayHandler::selectArrayFromOption($data, 'type', 'child', false, false, true, true, ':*');
$this->assertCount(2, $result);
$this->assertArrayHasKey('string_key:*0', $result);
$this->assertArrayHasKey('string_key:*child_key', $result);
}
public function testAllParametersCombined(): void
{
$data = [
'parent1' => [
'name' => 'Parent1',
'status' => 'ACTIVE',
'children' => [
'child1' => [
'name' => 'Child1',
'status' => 'active'
]
]
]
];
$result = ArrayHandler::selectArrayFromOption(
$data,
'status',
'active',
false, // not strict
true, // case insensitive
true, // recursive
true, // flat result
'|' // custom separator
);
$this->assertCount(2, $result);
$this->assertArrayHasKey('parent1', $result);
$this->assertArrayHasKey('parent1|children|child1', $result);
}
}
// __END__

View File

@@ -0,0 +1,328 @@
<?php
// This code was created by Claude Sonnet 4
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Combined\ArrayHandler;
class CoreLibsCombinedArrayHandlerSortArrayTest extends TestCase
{
/**
* Test basic ascending sort without maintaining keys
*/
public function testBasicAscendingSort()
{
$input = [3, 1, 4, 1, 5, 9];
$expected = [1, 1, 3, 4, 5, 9];
$result = ArrayHandler::sortArray($input);
$this->assertEquals($expected, $result);
$this->assertEquals(array_keys($expected), array_keys($result));
}
/**
* Test basic descending sort without maintaining keys
*/
public function testBasicDescendingSort()
{
$input = [3, 1, 4, 1, 5, 9];
$expected = [9, 5, 4, 3, 1, 1];
$result = ArrayHandler::sortArray($input, false, true);
$this->assertEquals($expected, $result);
$this->assertEquals(array_keys($expected), array_keys($result));
}
/**
* Test ascending sort with key maintenance
*/
public function testAscendingSortWithKeyMaintenance()
{
$input = ['c' => 3, 'a' => 1, 'd' => 4, 'b' => 1, 'e' => 5];
$expected = ['a' => 1, 'b' => 1, 'c' => 3, 'd' => 4, 'e' => 5];
$result = ArrayHandler::sortArray($input, false, false, true);
$this->assertEquals($expected, $result);
}
/**
* Test descending sort with key maintenance
*/
public function testDescendingSortWithKeyMaintenance()
{
$input = ['c' => 3, 'a' => 1, 'd' => 4, 'b' => 1, 'e' => 5];
$expected = ['e' => 5, 'd' => 4, 'c' => 3, 'a' => 1, 'b' => 1];
$result = ArrayHandler::sortArray($input, false, true, true);
$this->assertEquals($expected, $result);
}
/**
* Test string sorting with lowercase conversion
*/
public function testStringLowerCaseSort()
{
$input = ['Banana', 'apple', 'Cherry', 'date'];
$expected = ['apple', 'Banana', 'Cherry', 'date'];
$result = ArrayHandler::sortArray($input, true);
$this->assertEquals($expected, $result);
}
/**
* Test string sorting with lowercase conversion in reverse
*/
public function testStringLowerCaseSortReverse()
{
$input = ['Banana', 'apple', 'Cherry', 'date'];
$expected = ['date', 'Cherry', 'Banana', 'apple'];
$result = ArrayHandler::sortArray($input, true, true);
$this->assertEquals($expected, $result);
}
/**
* Test string sorting with lowercase conversion and key maintenance
*/
public function testStringLowerCaseSortWithKeys()
{
$input = ['b' => 'Banana', 'a' => 'apple', 'c' => 'Cherry', 'd' => 'date'];
$expected = ['a' => 'apple', 'b' => 'Banana', 'c' => 'Cherry', 'd' => 'date'];
$result = ArrayHandler::sortArray($input, true, false, true);
$this->assertEquals($expected, $result);
}
/**
* Test string sorting with lowercase conversion, reverse, and key maintenance
*/
public function testStringLowerCaseSortReverseWithKeys()
{
$input = ['b' => 'Banana', 'a' => 'apple', 'c' => 'Cherry', 'd' => 'date'];
$expected = ['d' => 'date', 'c' => 'Cherry', 'b' => 'Banana', 'a' => 'apple'];
$result = ArrayHandler::sortArray($input, true, true, true);
$this->assertEquals($expected, $result);
}
/**
* Test numeric string sorting with SORT_NUMERIC flag
*/
public function testNumericStringSorting()
{
$input = ['10', '2', '1', '20'];
$expected = ['1', '2', '10', '20'];
$result = ArrayHandler::sortArray($input, false, false, false, SORT_NUMERIC);
$this->assertEquals($expected, $result);
}
/**
* Test natural string sorting with SORT_NATURAL flag
*/
public function testNaturalStringSorting()
{
$input = ['img1.png', 'img10.png', 'img2.png', 'img20.png'];
$expected = ['img1.png', 'img2.png', 'img10.png', 'img20.png'];
$result = ArrayHandler::sortArray($input, false, false, false, SORT_NATURAL);
$this->assertEquals($expected, $result);
}
/**
* Test with empty array
*/
public function testEmptyArray()
{
$input = [];
$expected = [];
$result = ArrayHandler::sortArray($input);
$this->assertEquals($expected, $result);
}
/**
* Test with single element array
*/
public function testSingleElementArray()
{
$input = [42];
$expected = [42];
$result = ArrayHandler::sortArray($input);
$this->assertEquals($expected, $result);
}
/**
* Test with array containing null values
*/
public function testArrayWithNullValues()
{
$input = [3, null, 1, null, 2];
$expected = [null, null, 1, 2, 3];
$result = ArrayHandler::sortArray($input);
$this->assertEquals($expected, $result);
}
/**
* Test with mixed data types
*/
public function testMixedDataTypes()
{
$input = [3, '1', 4.5, '2', 1];
$result = ArrayHandler::sortArray($input);
// Should sort according to PHP's natural comparison rules
$this->assertIsArray($result);
$this->assertCount(5, $result);
}
/**
* Test that original array is not modified (immutability)
*/
public function testOriginalArrayNotModified()
{
$original = [3, 1, 4, 1, 5, 9];
$input = $original;
$result = ArrayHandler::sortArray($input);
$this->assertEquals($original, $input);
$this->assertNotEquals($input, $result);
}
/**
* Test case sensitivity without lowercase flag
*/
public function testCaseSensitivityWithoutLowercase()
{
$input = ['Banana', 'apple', 'Cherry'];
$result = ArrayHandler::sortArray($input);
// Capital letters should come before lowercase in ASCII sort
$this->assertEquals('Banana', $result[0]);
$this->assertEquals('Cherry', $result[1]);
$this->assertEquals('apple', $result[2]);
}
/**
* Test all parameters combination
*/
public function testAllParametersCombination()
{
$input = ['z' => 'Zebra', 'a' => 'apple', 'b' => 'Banana'];
$result = ArrayHandler::sortArray($input, true, true, true, SORT_REGULAR);
// Should be sorted by lowercase, reversed, with keys maintained
$keys = array_keys($result);
$values = array_values($result);
$this->assertEquals(['z', 'b', 'a'], $keys);
$this->assertEquals(['Zebra', 'Banana', 'apple'], $values);
}
/**
* Test floating point numbers
*/
public function testFloatingPointNumbers()
{
$input = [3.14, 2.71, 1.41, 1.73];
$expected = [1.41, 1.73, 2.71, 3.14];
$result = ArrayHandler::sortArray($input);
$this->assertEquals($expected, $result);
}
/**
* Test with duplicate values and key maintenance
*/
public function testDuplicateValuesWithKeyMaintenance()
{
$input = ['first' => 1, 'second' => 2, 'third' => 1, 'fourth' => 2];
$result = ArrayHandler::sortArray($input, false, false, true);
$this->assertCount(4, $result);
$this->assertEquals([1, 1, 2, 2], array_values($result));
// Keys should be preserved
$this->assertArrayHasKey('first', $result);
$this->assertArrayHasKey('second', $result);
$this->assertArrayHasKey('third', $result);
$this->assertArrayHasKey('fourth', $result);
}
/**
* Data provider for comprehensive parameter testing
*/
public function sortParameterProvider(): array
{
return [
'basic_ascending' => [
[3, 1, 4, 2],
false, false, false, SORT_REGULAR,
[1, 2, 3, 4]
],
'basic_descending' => [
[3, 1, 4, 2],
false, true, false, SORT_REGULAR,
[4, 3, 2, 1]
],
'lowercase_ascending' => [
['Banana', 'apple', 'Cherry'],
true, false, false, SORT_REGULAR,
['apple', 'Banana', 'Cherry']
],
'lowercase_descending' => [
['Banana', 'apple', 'Cherry'],
true, true, false, SORT_REGULAR,
['Cherry', 'Banana', 'apple']
]
];
}
/**
* Test various parameter combinations using data provider
*
* @dataProvider sortParameterProvider
*/
public function testSortParameterCombinations(
array $input,
bool $lowercase,
bool $reverse,
bool $maintainKeys,
int $params,
array $expected
) {
$result = ArrayHandler::sortArray($input, $lowercase, $reverse, $maintainKeys, $params);
if (!$maintainKeys) {
$this->assertEquals($expected, $result);
} else {
$this->assertEquals($expected, array_values($result));
}
}
}
// __END__

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,283 @@
<?php
// This code was created by Claude Sonnet 4
// FIX:
// '/test{/', // Unmatched brace -> this is valid
// '/test{1,}/', // Invalid quantifier -> this is valid
declare(strict_types=1);
namespace tests;
use PHPUnit\Framework\TestCase;
use CoreLibs\Convert\Strings;
/**
* Test class for CoreLibs\Convert\Strings regex validation methods
*/
class CoreLibsConvertStringsRegexValidateTest extends TestCase
{
/**
* Test isValidRegex with valid regex patterns
*/
public function testIsValidRegexWithValidPatterns(): void
{
$validPatterns = [
'/^[a-zA-Z0-9]+$/',
'/test/',
'/\d+/',
'/^hello.*world$/',
'/[0-9]{3}-[0-9]{3}-[0-9]{4}/',
'#^https?://.*#i',
'~^[a-z]+~',
'|test|',
'/^$/m',
'/\w+/u',
];
foreach ($validPatterns as $pattern) {
$this->assertTrue(
Strings::isValidRegex($pattern),
"Pattern '{$pattern}' should be valid"
);
}
}
/**
* Test isValidRegex with invalid regex patterns
*/
public function testIsValidRegexWithInvalidPatterns(): void
{
$invalidPatterns = [
'/[/', // Unmatched bracket
'/test[/', // Unmatched bracket
'/(?P<name>/', // Unmatched parenthesis
'/(?P<>test)/', // Invalid named group
'/test\\/', // Invalid escape at end
'/(test/', // Unmatched parenthesis
'/test)/', // Unmatched parenthesis
// '/test{/', // Unmatched brace -> this is valid
// '/test{1,}/', // Invalid quantifier -> this is valid
'/[z-a]/', // Invalid character range
'invalid', // No delimiters
'', // Empty string
'/(?P<123>test)/', // Invalid named group name
];
foreach ($invalidPatterns as $pattern) {
$this->assertFalse(
Strings::isValidRegex($pattern),
"Pattern '{$pattern}' should be invalid"
);
}
}
/**
* Test getLastRegexErrorString returns correct error messages
*/
public function testGetLastRegexErrorStringReturnsCorrectMessages(): void
{
// Test with a valid regex first to ensure clean state
Strings::isValidRegex('/valid/');
$this->assertEquals('No error', Strings::getLastRegexErrorString());
// Test with invalid regex to trigger an error
Strings::isValidRegex('/[/');
$errorMessage = Strings::getLastRegexErrorString();
// The error message should be one of the defined messages
$this->assertContains($errorMessage, array_values(Strings::PREG_ERROR_MESSAGES));
$this->assertNotEquals('Unknown error', $errorMessage);
}
/**
* Test getLastRegexErrorString with unknown error
*/
public function testGetLastRegexErrorStringWithUnknownError(): void
{
// This is harder to test directly since we can't easily mock preg_last_error()
// but we can test the fallback behavior by reflection or assume it works
// At minimum, ensure it returns a string
$result = Strings::getLastRegexErrorString();
$this->assertIsString($result);
$this->assertNotEmpty($result);
}
/**
* Test validateRegex with valid patterns
*/
public function testValidateRegexWithValidPatterns(): void
{
$validPatterns = [
'/^test$/',
'/\d+/',
'/[a-z]+/i',
];
foreach ($validPatterns as $pattern) {
$result = Strings::validateRegex($pattern);
$this->assertIsArray($result);
$this->assertArrayHasKey('valid', $result);
$this->assertArrayHasKey('preg_error', $result);
$this->assertArrayHasKey('error', $result);
$this->assertTrue($result['valid'], "Pattern '{$pattern}' should be valid");
$this->assertEquals(PREG_NO_ERROR, $result['preg_error']);
$this->assertNull($result['error']);
}
}
/**
* Test validateRegex with invalid patterns
*/
public function testValidateRegexWithInvalidPatterns(): void
{
$invalidPatterns = [
'/[/', // Unmatched bracket
'/(?P<name>/', // Unmatched parenthesis
'/test\\/', // Invalid escape at end
'/(test/', // Unmatched parenthesis
];
foreach ($invalidPatterns as $pattern) {
$result = Strings::validateRegex($pattern);
$this->assertIsArray($result);
$this->assertArrayHasKey('valid', $result);
$this->assertArrayHasKey('preg_error', $result);
$this->assertArrayHasKey('error', $result);
$this->assertArrayHasKey('pcre_error', $result);
$this->assertFalse($result['valid'], "Pattern '{$pattern}' should be invalid");
$this->assertNotEquals(PREG_NO_ERROR, $result['preg_error']);
$this->assertIsString($result['error']);
$this->assertNotNull($result['error']);
$this->assertNotEmpty($result['error']);
// Verify error message is from our defined messages or 'Unknown error'
$this->assertTrue(
in_array($result['error'], array_values(Strings::PREG_ERROR_MESSAGES)) ||
$result['error'] === 'Unknown error'
);
}
}
/**
* Test validateRegex array structure
*/
public function testValidateRegexArrayStructure(): void
{
$result = Strings::validateRegex('/test/');
// Test array structure for valid regex
$this->assertIsArray($result);
$this->assertCount(4, $result);
$this->assertArrayHasKey('valid', $result);
$this->assertArrayHasKey('preg_error', $result);
$this->assertArrayHasKey('error', $result);
$result = Strings::validateRegex('/[/');
// Test array structure for invalid regex
$this->assertIsArray($result);
$this->assertCount(4, $result);
$this->assertArrayHasKey('valid', $result);
$this->assertArrayHasKey('preg_error', $result);
$this->assertArrayHasKey('error', $result);
$this->assertArrayHasKey('pcre_error', $result);
}
/**
* Test that methods handle edge cases properly
*/
public function testEdgeCases(): void
{
// Empty string
$this->assertFalse(Strings::isValidRegex(''));
$result = Strings::validateRegex('');
$this->assertFalse($result['valid']);
// Very long pattern
$longPattern = '/' . str_repeat('a', 1000) . '/';
$this->assertTrue(Strings::isValidRegex($longPattern));
// Unicode patterns
$this->assertTrue(Strings::isValidRegex('/\p{L}+/u'));
$this->assertTrue(Strings::isValidRegex('/[α-ω]+/u'));
}
/**
* Test PREG_ERROR_MESSAGES constant accessibility
*/
public function testPregErrorMessagesConstant(): void
{
$this->assertIsArray(Strings::PREG_ERROR_MESSAGES);
$this->assertNotEmpty(Strings::PREG_ERROR_MESSAGES);
// Check that all expected PREG constants are defined
$expectedKeys = [
PREG_NO_ERROR,
PREG_INTERNAL_ERROR,
PREG_BACKTRACK_LIMIT_ERROR,
PREG_RECURSION_LIMIT_ERROR,
PREG_BAD_UTF8_ERROR,
PREG_BAD_UTF8_OFFSET_ERROR,
PREG_JIT_STACKLIMIT_ERROR,
];
foreach ($expectedKeys as $key) {
$this->assertArrayHasKey($key, Strings::PREG_ERROR_MESSAGES);
$this->assertIsString(Strings::PREG_ERROR_MESSAGES[$key]);
$this->assertNotEmpty(Strings::PREG_ERROR_MESSAGES[$key]);
}
}
/**
* Test error state isolation between method calls
*/
public function testErrorStateIsolation(): void
{
// Start with invalid regex
Strings::isValidRegex('/[/');
$firstError = Strings::getLastRegexErrorString();
$this->assertNotEquals('No error', $firstError);
// Use valid regex
Strings::isValidRegex('/valid/');
$secondError = Strings::getLastRegexErrorString();
$this->assertEquals('No error', $secondError);
// Verify validateRegex clears previous errors
$result = Strings::validateRegex('/valid/');
$this->assertTrue($result['valid']);
$this->assertEquals(PREG_NO_ERROR, $result['preg_error']);
}
/**
* Test various regex delimiters
*/
public function testDifferentDelimiters(): void
{
$patterns = [
'/test/', // forward slash
'#test#', // hash
'~test~', // tilde
'|test|', // pipe
'@test@', // at symbol
'!test!', // exclamation
'%test%', // percent
];
foreach ($patterns as $pattern) {
$this->assertTrue(
Strings::isValidRegex($pattern),
"Pattern with delimiter '{$pattern}' should be valid"
);
}
}
}
// __END__

View File

@@ -24,117 +24,83 @@ final class CoreLibsConvertStringsTest extends TestCase
{
// 0: input
// 1: format
// 2: split characters as string, null for default
// 3: expected
return [
'all empty string' => [
'',
'',
null,
''
],
'empty input string' => [
'',
'2-2',
null,
''
],
'empty format string string' => [
'1234',
'',
null,
'1234'
],
'string format match' => [
'1234',
'2-2',
null,
'12-34'
],
'string format trailing match' => [
'1234',
'2-2-',
null,
'12-34'
],
'string format leading match' => [
'1234',
'-2-2',
null,
'12-34'
],
'string format double inside match' => [
'1234',
'2--2',
null,
'12--34',
],
'string format short first' => [
'1',
'2-2',
null,
'1'
],
'string format match first' => [
'12',
'2-2',
null,
'12'
],
'string format short second' => [
'123',
'2-2',
null,
'12-3'
],
'string format too long' => [
'1234567',
'2-2',
null,
'12-34-567'
],
'string format invalid format string' => [
'1234',
'2_2',
null,
'1234'
],
'different split character' => [
'1234',
'2_2',
'_',
'12_34'
],
'mixed split characters' => [
'123456',
'2-2_2',
'-_',
'12-34_56'
],
'length mixed' => [
'ABCD12345568ABC13',
'2-4_5-2#4',
'-_#',
'AB-CD12_34556-8A#BC13'
],
'split with split chars in string' => [
'12-34',
'2-2',
null,
'12--3-4'
],
'mutltibyte string' => [
'あいうえ',
'2-2',
null,
'あいうえ'
],
'mutltibyte split string' => [
'1234',
'-',
null,
'1234'
],
];
}
@@ -143,29 +109,137 @@ final class CoreLibsConvertStringsTest extends TestCase
*
* @covers ::splitFormatString
* @dataProvider splitFormatStringProvider
* @testdox splitFormatString $input with format $format and splitters $split_characters will be $expected [$_dataName]
* @testdox splitFormatString $input with format $format will be $expected [$_dataName]
*
* @param string $input
* @param string $format
* @param string|null $split_characters
* @param string $expected
* @return void
*/
public function testSplitFormatString(
string $input,
string $format,
string $expected
): void {
$output = \CoreLibs\Convert\Strings::splitFormatString(
$input,
$format,
);
$this->assertEquals(
$expected,
$output
);
}
/** check exceptions */
public function splitFormatStringExceptionProvider(): array
{
return [
'string format with no splitter match' => [
'1234',
'22',
'12-34'
],
'invalid format string' => [
'1234',
'2あ2',
],
'mutltibyte string' => [
'あいうえ',
'2-2',
],
'mutltibyte split string' => [
'1234',
'-',
],
];
}
/**
* Undocumented function
*
* @covers ::splitFormatStringFixed
* @dataProvider splitFormatStringExceptionProvider
* @testdox splitFormatString Exception catch checks for $input with $format[$_dataName]
*
* @return void
*/
public function testSplitFormatStringExceptions(string $input, string $format): void
{
// catch exception
$this->expectException(\InvalidArgumentException::class);
\CoreLibs\Convert\Strings::splitFormatString($input, $format);
}
/**
* test for split Format string fixed length
*
* @return array
*/
public function splitFormatStringFixedProvider(): array
{
return [
'normal split, default split char' => [
'abcdefg',
4,
null,
'abcd-efg'
],
'noraml split, other single split char' => [
'abcdefg',
4,
"=",
'abcd=efg'
],
'noraml split, other multiple split char' => [
'abcdefg',
4,
"-=-",
'abcd-=-efg'
],
'non ascii characters' => [
'あいうえお',
2,
"-",
'あい-うえ-お'
],
'empty string' => [
'',
4,
"-",
''
]
];
}
/**
* Undocumented function
*
* @covers ::splitFormatStringFixed
* @dataProvider splitFormatStringFixedProvider
* @testdox splitFormatStringFixed $input with length $split_length and split chars $split_characters will be $expected [$_dataName]
*
* @param string $input
* @param int $split_length
* @param string|null $split_characters
* @param string $expected
* @return void
*/
public function testSplitFormatStringFixed(
string $input,
int $split_length,
?string $split_characters,
string $expected
): void {
if ($split_characters === null) {
$output = \CoreLibs\Convert\Strings::splitFormatString(
$output = \CoreLibs\Convert\Strings::splitFormatStringFixed(
$input,
$format
$split_length
);
} else {
$output = \CoreLibs\Convert\Strings::splitFormatString(
$output = \CoreLibs\Convert\Strings::splitFormatStringFixed(
$input,
$format,
$split_length,
$split_characters
);
}
@@ -175,6 +249,36 @@ final class CoreLibsConvertStringsTest extends TestCase
);
}
public function splitFormatStringFixedExceptionProvider(): array
{
return [
'split length too short' => [
'abcdefg',
-1,
],
'split length longer than string' => [
'abcdefg',
20,
],
];
}
/**
* Undocumented function
*
* @covers ::splitFormatStringFixed
* @dataProvider splitFormatStringFixedExceptionProvider
* @testdox splitFormatStringFixed Exception catch checks for $input with $length [$_dataName]
*
* @return void
*/
public function testSplitFormatStringFixedExceptions(string $input, int $length): void
{
// catch exception
$this->expectException(\InvalidArgumentException::class);
\CoreLibs\Convert\Strings::splitFormatStringFixed($input, $length);
}
/**
* Undocumented function
*
@@ -378,6 +482,222 @@ final class CoreLibsConvertStringsTest extends TestCase
\CoreLibs\Convert\Strings::stripUTF8BomBytes($file)
);
}
/**
* Undocumented function
*
* @return array
*/
public function allCharsInSetProvider(): array
{
return [
'find' => [
'abc',
'abcdef',
true
],
'not found' => [
'abcz',
'abcdef',
false
]
];
}
/**
* Undocumented function
*
* @covers ::allCharsInSet
* @dataProvider allCharsInSetProvider
* @testdox allCharsInSet $input in $haystack with expected $expected [$_dataName]
*
* @param string $needle
* @param string $haystack
* @param bool $expected
* @return void
*/
public function testAllCharsInSet(string $needle, string $haystack, bool $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Convert\Strings::allCharsInSet($needle, $haystack)
);
}
public function buildCharStringFromListsProvider(): array
{
return [
'test a' => [
'abc',
['a', 'b', 'c'],
],
'test b' => [
'abc123',
['a', 'b', 'c'],
['1', '2', '3'],
],
'test c: no params' => [
'',
],
'test c: empty 1' => [
'',
[]
],
'test nested' => [
'abc',
[['a'], ['b'], ['c']],
],
];
}
/**
* Undocumented function
*
* @covers ::buildCharStringFromLists
* @dataProvider buildCharStringFromListsProvider
* @testdox buildCharStringFromLists all $input convert to $expected [$_dataName]
*
* @param string $expected
* @param array ...$input
* @return void
*/
public function testBuildCharStringFromLists(string $expected, array ...$input): void
{
$this->assertEquals(
$expected,
\CoreLibs\Convert\Strings::buildCharStringFromLists(...$input)
);
}
/**
* Undocumented function
*
* @return array
*/
public function removeDuplicatesProvider(): array
{
return [
'test no change' => [
'ABCDEFG',
'ABCDEFG',
],
'test simple' => [
'aa',
'a'
],
'test keep lower and uppwer case' => [
'AaBbCc',
'AaBbCc'
],
'test unqiue' => [
'aabbcc',
'abc'
],
'test multibyte no change' => [
'あいうえお',
'あいうえお',
],
'test multibyte' => [
'ああいいううええおお',
'あいうえお',
],
'test multibyte special' => [
'あぁいぃうぅえぇおぉ',
'あぁいぃうぅえぇおぉ',
]
];
}
/**
* Undocumented function
*
* @covers ::removeDuplicates
* @dataProvider removeDuplicatesProvider
* @testdox removeDuplicates make $input unqiue to $expected [$_dataName]
*
* @param string $input
* @param string $expected
* @return void
*/
public function testRemoveDuplicates(string $input, string $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Convert\Strings::removeDuplicates($input)
);
}
/**
* Undocumented function
*
* @return array
*/
public function isValidRegexSimpleProvider(): array
{
return [
'valid regex' => [
'/^[A-z]$/',
true,
[
'valid' => true,
'preg_error' => 0,
'error' => null,
'pcre_error' => null
],
],
'invalid regex A' => [
'/^[A-z]$',
false,
[
'valid' => false,
'preg_error' => 1,
'error' => 'Internal PCRE error',
'pcre_error' => 'Internal error'
],
],
'invalid regex B' => [
'/^[A-z$',
false,
[
'valid' => false,
'preg_error' => 1,
'error' => 'Internal PCRE error',
'pcre_error' => 'Internal error'
],
],
];
}
/**
* Undocumented function
*
* @covers ::isValidRegexSimple
* @dataProvider isValidRegexSimpleProvider
* @testdox isValidRegexSimple make $input unqiue to $expected [$_dataName]
*
* @param string $input
* @param bool $expected
* @return void
*/
public function testIsValidRegexSimple(string $input, bool $expected, array $expected_extended): void
{
$this->assertEquals(
$expected,
\CoreLibs\Convert\Strings::isValidRegex($input),
'Regex is not valid'
);
$this->assertEquals(
$expected_extended,
\CoreLibs\Convert\Strings::validateRegex($input),
'Validation of regex failed'
);
$this->assertEquals(
// for true null is set, so we get here No Error
$expected_extended['error'] ?? \CoreLibs\Convert\Strings::PREG_ERROR_MESSAGES[0],
\CoreLibs\Convert\Strings::getLastRegexErrorString(),
'Cannot match last preg error string'
);
}
}
// __END__

View File

@@ -13,32 +13,6 @@ use PHPUnit\Framework\TestCase;
*/
final class CoreLibsCreateRandomKeyTest extends TestCase
{
/**
* Undocumented function
*
* @return array
*/
public function keyLenghtProvider(): array
{
return [
'valid key length' => [
0 => 6,
1 => true,
2 => 6,
],
'negative key length' => [
0 => -1,
1 => false,
2 => 4,
],
'tpp big key length' => [
0 => 300,
1 => false,
2 => 4,
],
];
}
/**
* Undocumented function
*
@@ -47,109 +21,67 @@ final class CoreLibsCreateRandomKeyTest extends TestCase
public function randomKeyGenProvider(): array
{
return [
'default key length' => [
// just key length
'default key length, default char set' => [
0 => null,
1 => 4
1 => \CoreLibs\Create\RandomKey::KEY_LENGTH_DEFAULT
],
'set -1 key length default' => [
'set -1 key length, default char set' => [
0 => -1,
1 => 4,
1 => \CoreLibs\Create\RandomKey::KEY_LENGTH_DEFAULT,
],
'set too large key length' => [
'set 0 key length, default char set' => [
0 => -1,
1 => \CoreLibs\Create\RandomKey::KEY_LENGTH_DEFAULT,
],
'set too large key length, default char set' => [
0 => 300,
1 => 4,
1 => \CoreLibs\Create\RandomKey::KEY_LENGTH_DEFAULT,
],
'set override key lenght' => [
'set override key lenght, default char set' => [
0 => 6,
1 => 6,
],
// just character set
'default key length, different char set A' => [
0 => \CoreLibs\Create\RandomKey::KEY_LENGTH_DEFAULT,
1 => \CoreLibs\Create\RandomKey::KEY_LENGTH_DEFAULT,
2 => [
'A', 'B', 'C'
],
],
'different key length, different char set B' => [
0 => 16,
1 => 16,
2 => [
'A', 'B', 'C'
],
3 => [
'1', '2', '3'
]
],
];
}
// Alternative more efficient version using strpos
/**
* 1
* check if all characters are in set
*
* @return array
* @param string $input
* @param string $allowed_chars
* @return bool
*/
public function keepKeyLengthProvider(): array
private function allCharsInSet(string $input, string $allowed_chars): bool
{
return [
'set too large' => [
0 => 6,
1 => 300,
2 => 6,
],
'set too small' => [
0 => 8,
1 => -2,
2 => 8,
],
'change valid' => [
0 => 10,
1 => 6,
2 => 6,
]
];
}
$inputLength = strlen($input);
/**
* run before each test and reset to default 4
*
* @before
*
* @return void
*/
public function resetKeyLength(): void
{
\CoreLibs\Create\RandomKey::setRandomKeyLength(4);
}
/**
* check that first length is 4
*
* @covers ::getRandomKeyLength
* @testWith [4]
* @testdox getRandomKeyLength on init will be $expected [$_dataName]
*
* @param integer $expected
* @return void
*/
public function testGetRandomKeyLengthInit(int $expected): void
{
$this->assertEquals(
$expected,
\CoreLibs\Create\RandomKey::getRandomKeyLength()
);
}
/**
* Undocumented function
*
* @covers ::setRandomKeyLength
* @covers ::getRandomKeyLength
* @dataProvider keyLenghtProvider
* @testdox setRandomKeyLength $input will be $expected, compare to $compare [$_dataName]
*
* @param integer $input
* @param boolean $expected
* @param integer $compare
* @return void
*/
public function testSetRandomKeyLength(int $input, bool $expected, int $compare): void
{
// set
$this->assertEquals(
$expected,
\CoreLibs\Create\RandomKey::setRandomKeyLength($input)
);
// read test, if false, use compare check
if ($expected === false) {
$input = $compare;
for ($i = 0; $i < $inputLength; $i++) {
if (strpos($allowed_chars, $input[$i]) === false) {
return false;
}
}
$this->assertEquals(
$input,
\CoreLibs\Create\RandomKey::getRandomKeyLength()
);
return true;
}
/**
@@ -163,43 +95,41 @@ final class CoreLibsCreateRandomKeyTest extends TestCase
* @param integer $expected
* @return void
*/
public function testRandomKeyGen(?int $input, int $expected): void
public function testRandomKeyGen(?int $input, int $expected, array ...$key_range): void
{
$__key_data = \CoreLibs\Create\RandomKey::KEY_CHARACTER_RANGE_DEFAULT;
if (count($key_range)) {
$__key_data = join('', array_unique(array_merge(...$key_range)));
}
if ($input === null) {
$this->assertEquals(
$expected,
strlen(\CoreLibs\Create\RandomKey::randomKeyGen())
);
} else {
} elseif ($input !== null && !count($key_range)) {
$random_key = \CoreLibs\Create\RandomKey::randomKeyGen($input);
$this->assertTrue(
$this->allCharsInSet($random_key, $__key_data),
'Characters not valid'
);
$this->assertEquals(
$expected,
strlen(\CoreLibs\Create\RandomKey::randomKeyGen($input))
strlen($random_key),
'String length not matching'
);
} elseif (count($key_range)) {
$random_key = \CoreLibs\Create\RandomKey::randomKeyGen($input, ...$key_range);
$this->assertTrue(
$this->allCharsInSet($random_key, $__key_data),
'Characters not valid'
);
$this->assertEquals(
$expected,
strlen($random_key),
'String length not matching'
);
}
}
/**
* Check that if set to n and then invalid, it keeps the previous one
* or if second change valid, second will be shown
*
* @covers ::setRandomKeyLength
* @dataProvider keepKeyLengthProvider
* @testdox keep setRandomKeyLength set with $input_valid and then $input_invalid will be $expected [$_dataName]
*
* @param integer $input_valid
* @param integer $input_invalid
* @param integer $expected
* @return void
*/
public function testKeepKeyLength(int $input_valid, int $input_invalid, int $expected): void
{
\CoreLibs\Create\RandomKey::setRandomKeyLength($input_valid);
\CoreLibs\Create\RandomKey::setRandomKeyLength($input_invalid);
$this->assertEquals(
$expected,
\CoreLibs\Create\RandomKey::getRandomKeyLength()
);
}
}
// __END__

View File

@@ -249,7 +249,7 @@ final class CoreLibsLoggingLoggingTest extends TestCase
$this->assertFalse(
$log->loggingLevelIsDebug()
);
// not set, should be debug]
// not set, should be debug
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetLoggingLevel',
'log_folder' => self::LOG_FOLDER,
@@ -297,6 +297,71 @@ final class CoreLibsLoggingLoggingTest extends TestCase
$log->setLoggingLevel('NotGood');
}
/**
* Undocumented function
*
* @covers ::setErrorLogWriteLevel
* @covers ::getErrorLogWriteLevel
* @testdox setErrorLogWriteLevel set/get checks
*
* @return void
*/
public function testSetErrorLogWriteLevel(): void
{
// valid that is not Debug
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetErrorLogWriteLevel',
'log_folder' => self::LOG_FOLDER,
'error_log_write_level' => Level::Error
]);
$this->assertEquals(
Level::Error,
$log->getErrorLogWriteLevel()
);
// not set on init
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetErrorLogWriteLevel',
'log_folder' => self::LOG_FOLDER,
]);
$this->assertEquals(
Level::Emergency,
$log->getErrorLogWriteLevel()
);
// invalid, should be Emergency, will throw excpetion too
$this->expectException(\InvalidArgumentException::class);
$this->expectExceptionMessage(
'Option: "error_log_write_level" is not of instance \CoreLibs\Logging\Logger\Level'
);
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetLoggingLevel',
'log_folder' => self::LOG_FOLDER,
'error_log_write_level' => 'I'
]);
$this->assertEquals(
Level::Emergency,
$log->getErrorLogWriteLevel()
);
// set valid then change
$log = new \CoreLibs\Logging\Logging([
'log_file_id' => 'testSetErrorLogWriteLevel',
'log_folder' => self::LOG_FOLDER,
'error_log_write_level' => Level::Error
]);
$this->assertEquals(
Level::Error,
$log->getErrorLogWriteLevel()
);
$log->setErrorLogWriteLevel(Level::Notice);
$this->assertEquals(
Level::Notice,
$log->getErrorLogWriteLevel()
);
// illegal logging level
$this->expectException(\Psr\Log\InvalidArgumentException::class);
$this->expectExceptionMessageMatches("/^Level \"NotGood\" is not defined, use one of: /");
$log->setErrorLogWriteLevel('NotGood');
}
// setLogFileId
// getLogFileId