%a';
- self::assertStringMatchesFormat($expectMatch, $output);
+ // \bdk\Debug::varDump('output', $output);
+ self::assertStringContainsString($expectStartsWith, self::normalizeString($output));
+ $expectMatch = '%a' . "\n"
+ . '%a';
+ // \bdk\Debug::varDump('expectMatch', $expectMatch);
+ // \bdk\Debug::varDump('output', $output);
+ self::assertStringMatchesFormatNormalized($expectMatch, $output);
$expectContains = '
Arguments = array(';
- self::assertStringContainsString($expectContains, $output);
+ self::assertStringContainsString($expectContains, self::normalizeString($output));
},
)
);
@@ -361,11 +466,26 @@ public function testTraceChars()
trace
- | | file | line | function |
+
+ |
+ file |
+ line |
+ function |
+
- | 0 | /var/w𝕨w/site/file.php | 123 | func |
- | 1 | /var/w𝕨w/site/𝓋endor/𝒻ile.php | 123 | func |
+
+ | 0 |
+ /var/w𝕨w/site/file.php |
+ 123 |
+ func |
+
+
+ | 1 |
+ /var/w𝕨w/site/𝓋endor/𝒻ile.php |
+ 123 |
+ func |
+
';
@@ -400,11 +520,23 @@ public function testTraceNoFunction()
trace
- | | file | line |
+
+ |
+ file |
+ line |
+
- | 0 | /var/w𝕨w/site/file.php | 123 |
- | 1 | /var/w𝕨w/site/𝓋endor/𝒻ile.php | 123 |
+
+ | 0 |
+ /var/w𝕨w/site/file.php |
+ 123 |
+
+
+ | 1 |
+ /var/w𝕨w/site/𝓋endor/𝒻ile.php |
+ 123 |
+
';
@@ -420,13 +552,13 @@ public function testInclInternal()
$this->testMethod(
'trace',
[
- \bdk\Debug::meta('inclInternal')
+ \bdk\Debug::meta('inclInternal'),
],
array(
'entry' => static function (LogEntry $logEntry) {
// bdk\AbstractDebug for php 5.x
// bdk\Debug for php 7.x +
- self::assertStringMatchesFormat('bdk\%ADebug->__call(\'trace\')', (string) $logEntry['args'][0][0][2]);
+ self::assertStringMatchesFormat('bdk\%ADebug->__call(\'trace\')', (string) $logEntry['args'][0]['rows'][0][3]);
},
)
);
diff --git a/tests/Debug/Plugin/PrettifyTest.php b/tests/Debug/Plugin/PrettifyTest.php
index 9d334fca..f51299cd 100644
--- a/tests/Debug/Plugin/PrettifyTest.php
+++ b/tests/Debug/Plugin/PrettifyTest.php
@@ -104,8 +104,7 @@ public function testPrettify()
-
-';
+';
$xml = $this->debug->prettify(\str_replace("\n", '', $xmlExpect), 'application/xml');
self::assertEquals(
new Abstraction(Type::TYPE_STRING, array(
diff --git a/tests/Debug/Route/ChromeLoggerTest.php b/tests/Debug/Route/ChromeLoggerTest.php
index a7243b79..a544fd43 100644
--- a/tests/Debug/Route/ChromeLoggerTest.php
+++ b/tests/Debug/Route/ChromeLoggerTest.php
@@ -32,7 +32,7 @@ public function tearDown(): void
'headerMaxPer' => null,
'route' => 'html',
));
- $this->debug->routeChromeLogger->setCfg('group', false);
+ $this->debug->getRoute('chromeLogger')->setCfg('group', false);
}
public function testUnableToFitToMax()
diff --git a/tests/Debug/Route/EmailTest.php b/tests/Debug/Route/EmailTest.php
index 3905aa76..f0862f48 100644
--- a/tests/Debug/Route/EmailTest.php
+++ b/tests/Debug/Route/EmailTest.php
@@ -30,14 +30,14 @@ public function testEmail()
$this->assertStringContainsString($stringExpect, self::$emailInfo['body']);
$data = \bdk\Debug\Utility\SerializeLog::unserialize(self::$emailInfo['body']);
$this->assertSame(array(
- 'config',
- 'version',
'alerts',
'classDefinitions',
+ 'config',
'log',
'logSummary',
'requestId',
'runtime',
+ 'version',
), \array_keys($data));
}
}
diff --git a/tests/Debug/Route/Html/ErrorSummaryTest.php b/tests/Debug/Route/Html/ErrorSummaryTest.php
index 62181f5f..74b4cd7a 100644
--- a/tests/Debug/Route/Html/ErrorSummaryTest.php
+++ b/tests/Debug/Route/Html/ErrorSummaryTest.php
@@ -110,16 +110,35 @@ public function testFatalBacktraceWithContext()
trace
- | | file | line | function |
+
+ |
+ file |
+ line |
+ function |
+
- | 0 | ' . \dirname(__FILE__) . '/' . '' . \basename(__FILE__) . ' | ' . $line1 . ' | Dingus::Dongus() |
- %a
-
|
+
+ | 0 |
+ ' . \dirname(__FILE__) . '/' . '' . \basename(__FILE__) . ' |
+ ' . $line1 . ' |
+ Dingus::Dongus() |
+
+
+ %a
+
|
+
- | 1 | ' . \dirname(__FILE__) . '/' . '' . \basename(__FILE__) . ' | ' . $line2 . ' | Meow::mix() |
- %a
-
|
+
+ | 1 |
+ ' . \dirname(__FILE__) . '/' . '' . \basename(__FILE__) . ' |
+ ' . $line2 . ' |
+ Meow::mix() |
+
+
+ %a
+
|
+
diff --git a/tests/Debug/Route/WampTest.php b/tests/Debug/Route/WampTest.php
index f6a43c7e..9aab9be5 100644
--- a/tests/Debug/Route/WampTest.php
+++ b/tests/Debug/Route/WampTest.php
@@ -53,40 +53,64 @@ public function testErrorWithTrace()
'error',
['Fatal Error', 'trace'],
array(
- 'caption' => 'trace',
- // 'evalLine' => null,
'file' => $this->file,
- 'inclArgs' => false,
'inclInternal' => false,
'limit' => 0,
'line' => $this->line,
- 'sortable' => false,
- 'tableInfo' => array(
- 'class' => null,
- 'columns' => array(
- array('key' => 'file'),
- array('key' => 'line'),
- array('key' => 'function'),
+ 'trace' => array(
+ 'caption' => 'trace',
+ 'debug' => Abstracter::ABSTRACTION,
+ 'header' => ['', 'file', 'line', 'function'],
+ 'meta' => array(
+ 'class' => null,
+ 'columns' => array(
+ array(
+ 'attribs' => array(
+ 'class' => ['t_key'],
+ 'scope' => 'row',
+ ),
+ 'key' => \bdk\Table\Factory::KEY_INDEX,
+ 'tagName' => 'th',
+ ),
+ array(
+ 'attribs' => array(
+ 'class' => ['no-quotes'],
+ ),
+ 'key' => 'file',
+ ),
+ array('key' => 'line'),
+ array('key' => 'function'),
+ ),
+ 'haveObjectRow' => false,
+ 'inclArgs' => false,
+ 'inclContext' => false,
+ 'sortable' => false,
),
- 'haveObjRow' => false,
- 'indexLabel' => null,
- 'rows' => array(),
- 'summary' => '',
+ 'rows' => [
+ [
+ 0,
+ array(
+ 'baseName' => 'file.php',
+ 'debug' => Abstracter::ABSTRACTION,
+ 'docRoot' => false,
+ 'pathCommon' => '',
+ 'pathRel' => '/path/to/',
+ 'type' => 'string',
+ 'typeMore' => 'filepath',
+ 'value' => null,
+ ),
+ 42,
+ array(
+ 'debug' => Abstracter::ABSTRACTION,
+ 'type' => 'identifier',
+ 'typeMore' => 'method',
+ 'value' => 'Foo::bar',
+ ),
+ ],
+ ],
+ 'type' => 'table',
+ 'value' => null,
),
- 'trace' => \array_map(static function ($frame) {
- $frame['file'] = (new Abstraction(Type::TYPE_STRING, array(
- 'typeMore' => Type::TYPE_STRING_FILEPATH,
- 'docRoot' => false,
- 'pathCommon' => '',
- 'pathRel' => \dirname($frame['file']) . '/',
- 'baseName' => \basename($frame['file']),
- )))->jsonSerialize();
- $frame['function'] = (new Abstraction(Type::TYPE_IDENTIFIER, array(
- 'typeMore' => Type::TYPE_IDENTIFIER_METHOD,
- 'value' => $frame['function'],
- )))->jsonSerialize();
- return \array_values($frame);
- }, $frames),
'uncollapse' => true,
),
],
@@ -97,7 +121,7 @@ public function testErrorWithTrace()
public function testCrateAbstraction()
{
$base64 = 'j/v9wNrF5i1abMXFW/4vVw==';
- $binary = \base64_decode($base64);
+ $binary = \base64_decode($base64, true);
$this->testMethod(
'log',
[
diff --git a/tests/Debug/ServiceProviderTest.php b/tests/Debug/ServiceProviderTest.php
index 8a46392b..19d97edc 100644
--- a/tests/Debug/ServiceProviderTest.php
+++ b/tests/Debug/ServiceProviderTest.php
@@ -64,7 +64,7 @@ public function testDebugConstruct()
self::assertInstanceOf('\bdk\Debug\Route\Text', $debug->getRoute('text'));
self::assertInstanceOf('\bdk\Debug\Dump\Html\Helper', $debug->getDump('html')->helper);
self::assertInstanceOf('\bdk\Debug\Dump\Html\HtmlObject', $debug->getDump('html')->valDumper->object);
- self::assertInstanceOf('\bdk\Debug\Dump\Html\Table', $debug->getDump('html')->table);
self::assertInstanceOf('\bdk\Debug\Dump\Html\Value', $debug->getDump('html')->valDumper);
+ self::assertInstanceOf('\bdk\Debug\Dump\Html\Table', $debug->getDump('html')->valDumper->table);
}
}
diff --git a/tests/Debug/Type/EnumTest.php b/tests/Debug/Type/EnumTest.php
index 9e8d08fd..4afa3799 100644
--- a/tests/Debug/Type/EnumTest.php
+++ b/tests/Debug/Type/EnumTest.php
@@ -145,11 +145,19 @@ public static function providerTestMethod()
'html' => '
- | | value |
+
+ |
+ |
+ value bdk\Test\Debug\Fixture\Enum\Meals |
+
- | enum | bdk\Test\Debug\Fixture\Enum\Meals::BREAKFAST |
+
+ | enum |
+ bdk\Test\Debug\Fixture\Enum\Meals |
+ bdk\Test\Debug\Fixture\Enum\Meals::BREAKFAST |
+
',
diff --git a/tests/Debug/Type/ObjectTest.php b/tests/Debug/Type/ObjectTest.php
index 2b5b7cc2..22f977c8 100644
--- a/tests/Debug/Type/ObjectTest.php
+++ b/tests/Debug/Type/ObjectTest.php
@@ -150,16 +150,17 @@ public static function providerTestMethod()
self::$testObj = new TestObj();
self::$testObj->methodPublic((object) array());
$abs1 = Debug::getInstance()->abstracter->getAbstraction(self::$testObj, 'log');
- $cratedAbs1 = $crate->crate($abs1);
- $cratedAbs1 = \bdk\Test\Debug\Helper::deObjectifyData($cratedAbs1);
// as provider method is static, but test is not static...
// we need to populate "scopeClass"
- $cratedAbs1['scopeClass'] = __CLASS__;
+ $abs1['scopeClass'] = __CLASS__;
+ $cratedAbs1 = $crate->crate($abs1);
+ $cratedAbs1 = \bdk\Test\Debug\Helper::deObjectifyData($cratedAbs1);
+ // $cratedAbs1['scopeClass'] = __CLASS__;
$abs2 = Debug::getInstance()->abstracter->getAbstraction(new \bdk\Test\Debug\Fixture\Test2(), 'log');
+ $abs2['scopeClass'] = __CLASS__;
$cratedAbs2 = $crate->crate($abs2);
$cratedAbs2 = \bdk\Test\Debug\Helper::deObjectifyData($cratedAbs2);
- $cratedAbs2['scopeClass'] = __CLASS__;
$tests = array(
'closure' => array(
diff --git a/tests/Debug/Type/StringTest.php b/tests/Debug/Type/StringTest.php
index d088d315..3aa73f55 100644
--- a/tests/Debug/Type/StringTest.php
+++ b/tests/Debug/Type/StringTest.php
@@ -12,6 +12,7 @@
/**
* PHPUnit tests for Debug class
*
+ * @covers \bdk\Debug\Abstraction\Abstraction
* @covers \bdk\Debug\Abstraction\AbstractString
* @covers \bdk\Debug\Dump\Base
* @covers \bdk\Debug\Dump\Base\Value
@@ -153,6 +154,7 @@ public static function providerTestMethod()
$binary = \base64_decode('j/v9wNrF5i1abMXFW/4vVw==', true);
+ // @phpcs:ignore SlevomatCodingStandard.Arrays.AlphabeticallySortedByKeys
$tests = array(
'basic' => array(
'log',
@@ -405,10 +407,10 @@ public static function providerTestMethod()
self::assertSame(Type::TYPE_STRING, $abs['type']);
self::assertSame(Type::TYPE_STRING_BINARY, $abs['typeMore']);
self::assertSame([
- ["utf8", "Brad:\nw𝔞s "],
- ["other", "80" ],
- ["utf8Control", "\x00"],
- ["utf8", "hеre" ],
+ ['utf8', "Brad:\nw𝔞s "],
+ ['other', '80' ],
+ ['utf8Control', "\x00"],
+ ['utf8', 'hеre' ],
], $abs['chunks']);
},
'html' => '<b>Brad</b>:
@@ -430,7 +432,8 @@ public static function providerTestMethod()
],
array(
'entry' => static function (LogEntry $logEntry) {
- $abs = $logEntry['args'][0]['binary'][0];
+ $tableAbs = $logEntry['args'][0];
+ $abs = $tableAbs['rows'][0][1];
$expect = array(
'brief' => false,
'percentBinary' => (float) 96,
@@ -445,14 +448,20 @@ public static function providerTestMethod()
'html' => '
- | | value |
+
+ |
+ value |
+
- | binary | string(binary)
-
- - size = 25
- - 00 00 00 00 01 01 00 00 00 00 00 00 00 00 00 f0 3f 00 00 00 00 00 00 00 40
- |
+
+ | binary |
+ string(binary)
+
+ - size = 25
+ - 00 00 00 00 01 01 00 00 00 00 00 00 00 00 00 f0 3f 00 00 00 00 00 00 00 40
+ |
+
',
@@ -465,7 +474,12 @@ public static function providerTestMethod()
'\u0000 / foo \\ bar', // both are single backslash
],
array(
- 'script' => 'console.log(' . \json_encode('\u0000 / foo \ bar', JSON_UNESCAPED_SLASHES). ');',
+ 'entry' => array(
+ 'method' => 'log',
+ 'args' => [ '\u0000 / foo \\ bar' ],
+ 'meta' => array(),
+ ),
+ 'script' => 'console.log(' . \json_encode('\u0000 / foo \ bar', JSON_UNESCAPED_SLASHES) . ');',
'text' => '\u0000 / foo \ bar',
),
),
diff --git a/tests/Debug/Utility/PhpTest.php b/tests/Debug/Utility/PhpTest.php
index ea024a16..baf21dde 100644
--- a/tests/Debug/Utility/PhpTest.php
+++ b/tests/Debug/Utility/PhpTest.php
@@ -141,8 +141,8 @@ public static function providerFriendlyClassName()
}
if (PHP_VERSION_ID >= 80100) {
$tests = \array_merge($tests, array(
- 'enum' => array(\bdk\Test\Debug\Fixture\Enum\Meals::BREAKFAST, 'bdk\Test\Debug\Fixture\Enum\Meals'),
'enum.backed' => array(\bdk\Test\Debug\Fixture\Enum\MealsBacked::BREAKFAST, 'bdk\Test\Debug\Fixture\Enum\MealsBacked'),
+ 'enum.pure' => array(\bdk\Test\Debug\Fixture\Enum\Meals::BREAKFAST, 'bdk\Test\Debug\Fixture\Enum\Meals'),
));
}
return $tests;
diff --git a/tests/Debug/Utility/PhpTypeTest.php b/tests/Debug/Utility/PhpTypeTest.php
index bb01ed56..c6e05a01 100644
--- a/tests/Debug/Utility/PhpTypeTest.php
+++ b/tests/Debug/Utility/PhpTypeTest.php
@@ -138,8 +138,8 @@ public static function providerGetDebugType()
}
if (PHP_VERSION_ID >= 80100) {
$tests = \array_merge($tests, array(
- 'enum' => array(\bdk\Test\Debug\Fixture\Enum\Meals::BREAKFAST, 'bdk\Test\Debug\Fixture\Enum\Meals::BREAKFAST'),
'enum.backed' => array(\bdk\Test\Debug\Fixture\Enum\MealsBacked::BREAKFAST, 'bdk\Test\Debug\Fixture\Enum\MealsBacked::BREAKFAST'),
+ 'enum.pure' => array(\bdk\Test\Debug\Fixture\Enum\Meals::BREAKFAST, 'bdk\Test\Debug\Fixture\Enum\Meals::BREAKFAST'),
));
}
return $tests;
diff --git a/tests/Debug/Utility/SerializeLogTest.php b/tests/Debug/Utility/SerializeLogTest.php
index dea3e3be..b1a2f624 100644
--- a/tests/Debug/Utility/SerializeLogTest.php
+++ b/tests/Debug/Utility/SerializeLogTest.php
@@ -2,14 +2,9 @@
namespace bdk\Test\Debug\Utility;
-use bdk\Debug;
-use bdk\Debug\Abstraction\Abstracter;
-use bdk\Debug\Abstraction\Type;
use bdk\Debug\Utility\SerializeLog;
-use bdk\HttpMessage\ServerRequestExtended as ServerRequest;
use bdk\PhpUnitPolyfill\AssertionTrait;
use bdk\Test\Debug\DebugTestFramework;
-use bdk\Test\Debug\Fixture\TestObj;
/**
* Test SerializeLog
@@ -17,6 +12,8 @@
* @covers \bdk\Debug\Abstraction\AbstractObject
* @covers \bdk\Debug\Abstraction\Object\Abstraction
* @covers \bdk\Debug\Utility\SerializeLog
+ * @covers \bdk\Debug\Utility\UnserializeLog
+ * @covers \bdk\Debug\Utility\UnserializeLogBackwards
*
* @phpcs:disable SlevomatCodingStandard.Arrays.AlphabeticallySortedByKeys.IncorrectKeyOrder
*/
@@ -24,122 +21,92 @@ class SerializeLogTest extends DebugTestFramework
{
use AssertionTrait;
- public function testSerializeUnserialize()
- {
- $debug = new Debug(array(
- 'collect' => true,
- 'logResponse' => false,
- 'serviceProvider' => array(
- 'serverRequest' => new ServerRequest(
- 'GET',
- null,
- array(
- 'DOCUMENT_ROOT' => TEST_DIR . '/../tmp',
- 'REQUEST_METHOD' => 'GET',
- 'REQUEST_TIME_FLOAT' => \microtime(true),
- 'SERVER_ADMIN' => 'testAdmin@test.com',
- )
- ),
- ),
- ));
- $debug->alert('some alert');
- $debug->groupSummary();
- $debug->log('in summary');
- $debug->log(new TestObj());
- $debug->groupEnd();
- $debug->info('this is a test');
- $serialized = SerializeLog::serialize($debug);
- $unserialized = SerializeLog::unserialize($serialized);
- self::assertIsArray($unserialized);
- $channelNameRoot = $debug->getCfg('channelName', Debug::CONFIG_DEBUG);
- $expect = array(
- 'alerts' => $this->helper->deObjectifyData($debug->data->get('alerts'), false),
- 'classDefinitions' => $this->helper->deObjectifyData($debug->data->get('classDefinitions')),
- 'config' => array(
- 'channelIcon' => $debug->getCfg('channelIcon', Debug::CONFIG_DEBUG),
- 'channelKey' => $debug->getCfg('channelKey', Debug::CONFIG_DEBUG),
- 'channelName' => $channelNameRoot,
- 'channels' => \array_map(static function (Debug $channel) use ($channelNameRoot) {
- $channelName = $channel->getCfg('channelName', Debug::CONFIG_DEBUG);
- return array(
- 'channelIcon' => $channel->getCfg('channelIcon', Debug::CONFIG_DEBUG),
- 'channelShow' => $channel->getCfg('channelShow', Debug::CONFIG_DEBUG),
- 'channelSort' => $channel->getCfg('channelSort', Debug::CONFIG_DEBUG),
- 'nested' => \strpos($channelName, $channelNameRoot . '.') === 0,
- );
- }, $debug->getChannels(true, true)),
- 'logRuntime' => $debug->getCfg('logRuntime'),
- ),
- 'log' => $this->helper->deObjectifyData($debug->data->get('log'), false, true),
- 'logSummary' => $this->helper->deObjectifyData($debug->data->get('logSummary'), false, true),
- 'runtime' => $debug->data->get('runtime'),
- 'requestId' => $debug->data->get('requestId'),
- 'version' => Debug::VERSION,
- );
- $actual = $this->helper->deObjectifyData($unserialized);
-
- self::assertSame(array(
- "\x00default\x00",
- 'bdk\\Test\\Debug\\Fixture\\TestObj',
- 'stdClass',
- ), \array_keys($unserialized['classDefinitions']));
-
- self::assertEquals($expect, $actual);
- $debug = SerializeLog::import($unserialized);
- $objAbs = $debug->data->get('logSummary.0.1.args.0');
- self::assertInstanceOf('bdk\\Debug\\Abstraction\\Abstraction', $objAbs);
- self::assertSame(
- $debug->data->get(array('classDefinitions', 'bdk\\Test\\Debug\\Fixture\\TestObj')),
- \bdk\Debug\Utility\Reflection::propGet($objAbs, 'inherited')
- );
- $serialized = SerializeLog::serialize($debug);
- $unserialized = SerializeLog::unserialize($serialized);
- self::assertEquals(
- $expect,
- $this->helper->deObjectifyData($unserialized)
- );
- }
-
/**
- * Simply test that importing and outputting log serialized with older versions of PHPDebugConsole does not throw an error.
- *
- * @doesNotPerformAssertions
- *
- * @dataProvider BackwardsCompatibilityDataProvider
+ * @dataProvider importProvider
*/
- public function testBackwardsImportCompatibility($dataFilepath)
+ public function testImport($version, $dataFilepath)
{
$serialized = \file_get_contents($dataFilepath);
$data = SerializeLog::unserialize($serialized);
+
+ if ($version === '2.3') {
+ $data['runtime']['memoryLimit'] = '2G';
+ }
+
$debug = SerializeLog::import($data);
- $debug->setCfg(array(
- 'output' => true,
- 'route' => 'html',
- ));
- $debug->output();
+
+ // now "export" what we just imported and compare to expected
+
+ $serialized = SerializeLog::serialize($debug);
+ $data = SerializeLog::unserialize($serialized);
+
+ $dataExpect = include TEST_DIR . '/Debug/data/serialized/expected.php';
+
+ if ($version === '3.1') {
+ unset($data['classDefinitions']['Simple']['cfgFlags']);
+ }
+ if ($version === '3.0' || $version === '2.3') {
+ unset($data['classDefinitions']['Simple']['cfgFlags']);
+ $nullify = [
+ 'methods.__toString.declaredLast',
+ 'methods.__toString.declaredOrig',
+ 'methods.foo.declaredLast',
+ 'methods.foo.declaredOrig',
+ 'properties.offLimits.declaredLast',
+ 'properties.offLimits.declaredOrig',
+ ];
+ foreach ($nullify as $path) {
+ \bdk\Debug\Utility\ArrayUtil::pathSet($dataExpect['classDefinitions']['Simple'], $path, null);
+ }
+ }
+ if ($version === '2.3') {
+ unset($dataExpect['classDefinitions']['Simple']['implements']);
+ $dataExpect['log'][1][1][0]['object']['scopeClass'] = 'bdk\Debug';
+ \ksort($dataExpect['log'][1][1][0]['object']);
+ $dataExpect['log'][1][1][0]['string (timestamp)'] = (string) \strtotime('2026-01-01 12:34:56 UTC');
+ }
+
+ // \bdk\Debug::varDump('expect', $dataExpect);
+ // \bdk\Debug::varDump('actual', $this->helper->deObjectifyData($data, false));
+
+ self::assertSame($dataExpect, $this->helper->deObjectifyData($data, false));
}
- public static function BackwardsCompatibilityDataProvider()
+ public static function importProvider()
{
$dataDir = TEST_DIR . '/Debug/data/serialized/';
$dataFiles = \glob($dataDir . '*.txt');
$tests = array();
foreach ($dataFiles as $filepath) {
$basename = \basename($filepath, '.txt');
+ $version = \preg_replace('/[^\d]+$/', '', $basename);
$tests[$basename] = array(
+ $version,
$filepath,
);
}
- // if (PHP_VERSION_ID < 50500) {
- // return array();
- // }
- if (PHP_VERSION_ID < 80000) {
+ if (PHP_VERSION_ID < 70400) {
+ // objects serialized with __serialize can not be unserialized in php < 7.4
+ // v2.3 did not use __serialize, so can still test that
return \array_intersect_key($tests, \array_flip(['2.3']));
}
+
+ /*
+ return \array_intersect_key($tests, \array_flip([
+ '2.3',
+ '3.0',
+ '3.1',
+ '3.2',
+ '3.3',
+ '3.4',
+ '3.5',
+ '3.6',
+ ]));
+ */
return $tests;
}
- public function testSerialieNotBase64()
+ public function testSerializeNotBase64()
{
$this->debug->alert('some alert');
$this->debug->groupSummary();
@@ -152,337 +119,8 @@ public function testSerialieNotBase64()
if (\preg_match($regex, $serialized, $matches)) {
$serialized = $matches[1];
}
- $serialized = \base64_decode($serialized);
+ $serialized = \base64_decode($serialized, true);
$unserialized = SerializeLog::unserialize($serialized);
self::assertFalse($unserialized);
}
-
- public function testUnserializeLogLegacy()
- {
- $serialized = <<<'EOD'
-START DEBUG
-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
-END DEBUG
-EOD;
- $unserialized = SerializeLog::unserialize($serialized);
- $expectUnserialized = array(
- 'config' => array(
- 'channels' => array(),
- 'channelName' => 'general',
- ),
- 'version' => '2.3',
- 'alerts' => array(
- array(
- 'alert',
- array('Alerty'),
- array(
- 'class' => 'danger',
- 'dismissible' => false,
- ),
- ),
- ),
- 'log' => array(
- array(
- 'log',
- array('hello world'),
- array(),
- ),
- array(
- 'log',
- array(
- 'some obj',
- array(
- 'className' => 'stdClass',
- 'collectMethods' => true,
- 'constants' => array(),
- 'debug' => Abstracter::ABSTRACTION,
- 'debugMethod' => 'log',
- 'definition' => array(
- 'fileName' => false,
- 'startLine' => false,
- 'extensionName' => 'Core',
- ),
- 'extends' => array(),
- 'implements' => array(),
- 'isExcluded' => false,
- 'isRecursion' => false,
- 'methods' => array(),
- 'phpDoc' => array(
- 'summary' => null,
- 'desc' => null,
- ),
- 'properties' => array(
- 'foo' => array(
- 'desc' => null,
- 'inheritedFrom' => null,
- 'isExcluded' => false,
- 'isStatic' => false,
- 'originallyDeclared' => null,
- 'overrides' => null,
- 'forceShow' => false,
- 'type' => null,
- 'value' => 'bar',
- 'valueFrom' => 'value',
- 'visibility' => 'public',
- // import merges in default values
- // 'attributes' => array(),
- // 'debugInfoExcluded' => false,
- // 'isPromoted' => false,
- // 'isReadOnly' => false,
- ),
- ),
- 'scopeClass' => 'bdk\Debug',
- 'stringified' => null,
- 'type' => Type::TYPE_OBJECT,
- 'traverseValues' => array(),
- 'viaDebugInfo' => false,
- ),
- ),
- array(),
- ),
- ),
- 'logSummary' => array(
- array(
- array(
- 'group',
- array('environment'),
- array(
- 'hideIfEmpty' => true,
- 'level' => 'info',
- ),
- ),
- array(
- 'log',
- array(
- 'PHP Version',
- '8.1.0',
- ),
- array(),
- ),
- array(
- 'log',
- array(
- 'ini location',
- '/usr/local/etc/php/8.1/php.ini',
- ),
- array(),
- ),
- array(
- 'log',
- array(
- 'memory_limit',
- '1 GB',
- ),
- array(),
- ),
- array(
- 'log',
- array(
- 'session.cache_limiter',
- 'nocache',
- ),
- array(),
- ),
- array(
- 'log',
- array(
- 'session_save_path',
- '/var/tmp/',
- ),
- array(),
- ),
- array(
- 'warn',
- array(
- 'PHP\'s %cerror_reporting%c is set to `%cE_ALL | E_STRICT & ~E_DEPRECATED%c` rather than `%cE_ALL | E_STRICT%c`' . "\n"
- . 'PHPDebugConsole is disregarding %cerror_reporting%c value (this is configurable)',
- 'font-family:monospace; opacity:0.8;',
- 'font-family:inherit; white-space:pre-wrap;',
- 'font-family:monospace; opacity:0.8;',
- 'font-family:inherit; white-space:pre-wrap;',
- 'font-family:monospace; opacity:0.8;',
- 'font-family:inherit; white-space:pre-wrap;',
- 'font-family:monospace; opacity:0.8;',
- 'font-family:inherit; white-space:pre-wrap;',
- ),
- array(
- 'file' => null,
- 'line' => null,
- ),
- ),
- array(
- 'log',
- array(
- '$_SERVER',
- array(
- 'REMOTE_ADDR' => '127.0.0.1',
- 'REQUEST_TIME' => '2022-03-21 03:19:25 UTC',
- 'REQUEST_URI' => '/common/vendor/bdk/PHPDebugConsole/examples/ver23.php',
- 'SERVER_ADDR' => '127.0.0.1',
- 'SERVER_NAME' => '127.0.0.1',
- ),
- ),
- array(),
- ),
- array(
- 'log',
- array(
- 'request headers',
- array(
- 'Accept' => 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
- 'Accept-Encoding' => 'gzip, deflate, br',
- 'Accept-Language' => 'en-US,en;q=0.9',
- 'Cache-Control' => 'max-age=0',
- 'Connection' => 'keep-alive',
- 'Cookie' => 'undefined=undefined; SESSIONID=hp5ln6mia3bjrgkjpsn8usta8b;',
- 'Host' => '127.0.0.1',
- 'Sec-Fetch-Dest' => 'document',
- 'Sec-Fetch-Mode' => 'navigate',
- 'Sec-Fetch-Site' => 'none',
- 'Sec-Fetch-User' => '?1',
- 'Upgrade-Insecure-Requests' => '1',
- 'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.83 Safari/537.36',
- 'dnt' => '1',
- 'sec-ch-ua' => '" Not A;Brand";v="99", "Chromium";v="99", "Google Chrome";v="99"',
- 'sec-ch-ua-mobile' => '?0',
- 'sec-ch-ua-platform' => '"macOS"',
- 'sec-gpc' => '1',
- ),
- ),
- array(),
- ),
- array(
- 'log',
- array(
- '$_COOKIE',
- array(
- 'SESSIONID' => 'hp5ln6mia3bjrgkjpsn8usta8b',
- 'undefined' => 'undefined',
- ),
- ),
- array(),
- ),
- array(
- 'groupEnd',
- array(),
- array(),
- ),
- ),
- ),
- 'runtime' => array(),
- 'config' => array(
- 'channels' => array(),
- 'channelName' => 'general',
- ),
- );
- self::assertSame($expectUnserialized, $unserialized);
-
- $debug = SerializeLog::import($unserialized);
-
- /*
- Now test that imported log serializes as expected
- */
-
- $expect = $expectUnserialized;
-
- unset($expect['log'][1][1][1]['collectMethods']);
- // unset($expect['logSummary'][0][6][2]); // remove empty meta (null meta no longer stored as of 3.4)
- // serialized did not include these values
- $expect['log'][1][1][1] = \array_merge(
- array(
- 'attributes' => array(),
- 'cases' => array(),
- 'cfgFlags' => 29360127,
- 'interfacesCollapse' => array(),
- 'isAbstract' => false,
- 'isAnonymous' => false,
- 'isFinal' => false,
- 'isInterface' => false,
- 'isLazy' => false,
- 'isMaxDepth' => false,
- 'isReadOnly' => false,
- 'isTrait' => false,
- 'methodsWithStaticVars' => array(),
- 'sectionOrder' => array(
- 'attributes',
- 'extends',
- 'implements',
- 'constants',
- 'cases',
- 'properties',
- 'methods',
- 'phpDoc',
- ),
- 'sort' => 'inheritance visibility name',
- 'keys' => array(),
- 'typeMore' => null,
- ),
- $expect['log'][1][1][1]
- );
- // serialized did not include these values
- $expect['log'][1][1][1]['properties']['foo'] = \array_merge(
- array(
- 'attributes' => array(),
- 'declaredLast' => null,
- 'declaredPrev' => null,
- 'declaredOrig' => null,
- 'debugInfoExcluded' => false,
- 'hooks' => array(),
- 'isDeprecated' => false,
- 'isFinal' => false,
- 'isPromoted' => false,
- 'isReadOnly' => false,
- 'isVirtual' => false,
- 'phpDoc' => array(
- 'desc' => '',
- 'summary' => '',
- ),
- ),
- $expect['log'][1][1][1]['properties']['foo']
- );
-
- $serialized = SerializeLog::serialize($debug);
- $unserialized = SerializeLog::unserialize($serialized);
-
- $keysCompare = array('alerts', 'log', 'logSummary');
- foreach ($expect['log'] as $i => $logEntryArray) {
- if (empty($logEntryArray[2])) {
- unset($expect['log'][$i][2]);
- }
- }
- foreach ($expect['logSummary'][0] as $i => $logEntryArray) {
- if (empty($logEntryArray[2])) {
- unset($expect['logSummary'][0][$i][2]);
- }
- }
-
- $expect = \array_intersect_key($expect, \array_flip($keysCompare));
- \ksort($expect['log'][1][1][1]);
- \ksort($expect['log'][1][1][1]['properties']['foo']);
- $actual = \array_intersect_key(
- $this->helper->deObjectifyData($unserialized, true, false, true),
- \array_flip($keysCompare)
- );
-
- // \bdk\Debug::varDump('expect', print_r($expect, true));
- // \bdk\Debug::varDump('actual', print_r($actual, true));
- self::assertEquals($expect, $actual);
- }
}
diff --git a/tests/Debug/data/ConfusableIdentifiers.php b/tests/Debug/data/ConfusableIdentifiers.php
index 9007be01..c2c49252 100644
--- a/tests/Debug/data/ConfusableIdentifiers.php
+++ b/tests/Debug/data/ConfusableIdentifiers.php
@@ -542,7 +542,6 @@
),
'sort' => 'inheritance visibility name',
'stringified' => null,
- 'traverseValues' => array(),
'type' => Type::TYPE_OBJECT,
'typeMore' => null,
'viaDebugInfo' => false,
diff --git a/tests/Debug/data/PropertyAsymVisibility.php b/tests/Debug/data/PropertyAsymVisibility.php
index d88a952a..c8e1c9ca 100644
--- a/tests/Debug/data/PropertyAsymVisibility.php
+++ b/tests/Debug/data/PropertyAsymVisibility.php
@@ -124,7 +124,7 @@
),
'sort' => 'inheritance visibility name',
'stringified' => null,
- 'traverseValues' => array(),
+ // 'traverseValues' => array(),
'type' => Type::TYPE_OBJECT,
'typeMore' => null,
'viaDebugInfo' => false,
diff --git a/tests/Debug/data/PropertyHooks.php b/tests/Debug/data/PropertyHooks.php
index abeb7392..52923cb5 100644
--- a/tests/Debug/data/PropertyHooks.php
+++ b/tests/Debug/data/PropertyHooks.php
@@ -253,7 +253,7 @@
),
'sort' => 'inheritance visibility name',
'stringified' => null,
- 'traverseValues' => array(),
+ // 'traverseValues' => array(),
'type' => Type::TYPE_OBJECT,
'typeMore' => null,
'viaDebugInfo' => false,
diff --git a/tests/Debug/data/serialized/2.3.txt b/tests/Debug/data/serialized/2.3.txt
index 5f50d3b7..4462c43f 100644
--- a/tests/Debug/data/serialized/2.3.txt
+++ b/tests/Debug/data/serialized/2.3.txt
@@ -1,21 +1,17 @@
-Request: GET /someAction
-
START DEBUG
-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
-END DEBUG
+zVfbjts2EM1DX9qvUIWiSR66tuS7HARI7aRddNe7qJsWBQoEtERbbChSIanNOoH/pd/SL+sML/Il3rSPBWxDpMjDM2cuHJNsmH3U8BMTTpXR8ZRkSfaRZV146LkH
+nQ3863jKsmS/QmcJvFlSxQhnH2hkSqa/jqc7lqWwKEVgeJ9zogHXHlIQsaEKB0kCI6YrpjVbcRpPVwC42+00nBpzuUEi/XNENko29adE+kBRKbKNJNIQG93y6GYf
+dzu3vMUJZxyhkGyClJM0i1dSckrEhVGNpZbgEb39/Jpw7TlbMCasNiNHcc0lgXEBUL2L/gAmgZ1oOI+nC6eDXP1Jc2PFHuOZEy/TglTUS7VkVc3tAG3LJeew45qa
+UhY6UMJtUmhDhPMcmmoZFHTVbHDvKIsf2cGjVnQcOZz4QAl42cWXayaYYVLETi6djcEexmlgNoENndeaKt1ZvaXCdK7YShG17cy4bIqlkYpsaGeuZL2S950NM7Cs
+kCaXVef2x9s5Hj4DyiBjh94TNFF3dIigi7qsY2cXGKXMFRPUOmns9af3hgoN9BwdGzPWSPuiOBABrbEKVvRIHDuvX97nvCloEVyIwjD9M80bpa3xbhqAq6C4D2jc
+/+aNkUujIMqsB7th/vC8hWfMRAnWGVq8UrLy05bCi5U2imAQeAopzs5prWhOzJ7aCKdfMUF4mBnjzNIQw/IwBfFSE0WqA0NxqqznMm+pA5Juqgqc5Xj00d86x4EX
+5o5BMjLOzNYHYd2sOJ7iFFLUNEr8SnhDQ8Bcmsc6uiYbXORydy1l3KbS/0eUBPlgBhOFw2HI9JA/LqAW/kzIA9JwszcVrH/UCJsetLC51KqnsxROMiWNtI2JaCub
+6D1ARkZGVo1g3U2NmbXnjFXBpxU8fmOp2UezrUMZ0D7Odqcu7Z26FMyDvHklZcR0RKJasTuQLHIBDEWRmKiQVAPLZr2Oj/1vsZ1723A5z+PI8MQbDlbSIjqk+mk0
+AVVP6Ywx/zE+aygrcA0xuncpmCzX6ytWMX95JZ773rTPRtxpJTgTR1CiY6nYBsONb+cUKrXCDQtXqeQdVYoVVLcza6lyuizl+wNHOykX7oK4C3GVQqxdPq4O3OVN
+3PoyaFc6zsc7/11gXKFzQJuFCxjwVsXbP+bhcsCodk5jaxYsOnZ7uKjcLQS5CcZqavPisKimSIZY4Euxlm1lPgqcBIV8RqvnrnbqZx14frZSUef5V19uqInAnobw
+aA2VX//91/sS/KVrktNv4dyCTiMiigjy1SjJv8tLoqKSbUoOX4Np96RET0T2B4OyfamffhGC1WfoE9FUEA75U+uDLO6nsfdzWGBYRaEuVPXTIHYyGo7SUXc8GaK8
+R61FethajH2L8lIUob/AZUcbeic9jSG2BTrpRoYH7Y/1S7739AvDocIQHxXA1FBvyw8vAuNa1g0n7jJnWX+UDtJ0uu+ETiG/h7JAuDwDufj9PGQ6GE666XSvwCnk
+rGQ52ZyDvLx6AHLU7U8G4+lepCNMcOGcijvXQp5Azm7OQw4nve6wi4j98yyXlBjjWq0TyN8e0BJI9gbW8MEZSAD5peH6nHNufnrAOd1ed2L7X6dl39fDnNRuiUvW
+23aT9tyhL2wqcZCKGMNS+YBqu0QjDeEzyduFu1AhoPlbhqLrYy9xBfmk9e5jEcXUPu28Jxg6jJuIiQgbXvhG1efb74ewUiB0S8lbuLQqqbZRo6GZvLi4aMES35Fq
+gl3qh/3fhp01U9F3UJfMpe1sx3gHkGJF6dqLpRqBed3envjvxZ2Eh77Gw/zGJAUr4BOEd6vsLeOvwCQdX5/CFlkXrbe3FbZLUppZSYSg3K/cUEEV3v+7fwA=
+END DEBUG
\ No newline at end of file
diff --git a/tests/Debug/data/serialized/3.0.txt b/tests/Debug/data/serialized/3.0.txt
index 9071a11e..df62e78f 100644
--- a/tests/Debug/data/serialized/3.0.txt
+++ b/tests/Debug/data/serialized/3.0.txt
@@ -1,42 +1,21 @@
-Request: GET http://127.0.0.1/someAction
-
START DEBUG
-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
-END DEBUG
+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
+END DEBUG
\ No newline at end of file
diff --git a/tests/Debug/data/serialized/3.1.txt b/tests/Debug/data/serialized/3.1.txt
index bda8ebd3..fa8e72bb 100644
--- a/tests/Debug/data/serialized/3.1.txt
+++ b/tests/Debug/data/serialized/3.1.txt
@@ -1,44 +1,22 @@
-Request: GET http://127.0.0.1/someAction
-
START DEBUG
-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
-END DEBUG
+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
+ygAfQ0JDIv4D
+END DEBUG
\ No newline at end of file
diff --git a/tests/Debug/data/serialized/3.2.txt b/tests/Debug/data/serialized/3.2.txt
index b6309755..d73900f2 100644
--- a/tests/Debug/data/serialized/3.2.txt
+++ b/tests/Debug/data/serialized/3.2.txt
@@ -1,46 +1,24 @@
-Request: GET http://127.0.0.1/someAction
-
START DEBUG
-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
-END DEBUG
+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
+END DEBUG
\ No newline at end of file
diff --git a/tests/Debug/data/serialized/3.3.txt b/tests/Debug/data/serialized/3.3.txt
index f64258ba..99398a56 100644
--- a/tests/Debug/data/serialized/3.3.txt
+++ b/tests/Debug/data/serialized/3.3.txt
@@ -1,48 +1,24 @@
-Request: GET http://127.0.0.1/someAction
-
START DEBUG
-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
-END DEBUG
+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
+END DEBUG
\ No newline at end of file
diff --git a/tests/Debug/data/serialized/3.4.txt b/tests/Debug/data/serialized/3.4.txt
index ab5dd361..24a64d69 100644
--- a/tests/Debug/data/serialized/3.4.txt
+++ b/tests/Debug/data/serialized/3.4.txt
@@ -1,48 +1,24 @@
-Request: GET http://127.0.0.1/someAction
-
START DEBUG
-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
-END DEBUG
+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
+END DEBUG
\ No newline at end of file
diff --git a/tests/Debug/data/serialized/3.5.txt b/tests/Debug/data/serialized/3.5.txt
index a8394236..d0868265 100644
--- a/tests/Debug/data/serialized/3.5.txt
+++ b/tests/Debug/data/serialized/3.5.txt
@@ -1,48 +1,24 @@
-Request: GET http://127.0.0.1/someAction
-
START DEBUG
-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
-END DEBUG
+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
+END DEBUG
\ No newline at end of file
diff --git a/tests/Debug/data/serialized/3.6.txt b/tests/Debug/data/serialized/3.6.txt
new file mode 100644
index 00000000..394360e3
--- /dev/null
+++ b/tests/Debug/data/serialized/3.6.txt
@@ -0,0 +1,25 @@
+START DEBUG
+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
+1cvJO+dfCytgLtScsD0BTEtOVaP6Fw==
+END DEBUG
\ No newline at end of file
diff --git a/tests/Debug/data/serialized/expected.php b/tests/Debug/data/serialized/expected.php
new file mode 100644
index 00000000..a651af62
--- /dev/null
+++ b/tests/Debug/data/serialized/expected.php
@@ -0,0 +1,353 @@
+ array(
+ 0 => array(
+ 0 => 'alert',
+ 1 => array(
+ 0 => 'Serialize this!',
+ ),
+ 2 => array(
+ 'dismissible' => false,
+ 'level' => 'error',
+ ),
+ ),
+ ),
+ 'classDefinitions' => array(
+ '' . "\0" . 'default' . "\0" . '' => array(
+ '__isUsed' => true,
+ 'attributes' => array(
+ ),
+ 'cases' => array(
+ ),
+ 'cfgFlags' => 29360127,
+ 'className' => '' . "\0" . 'default' . "\0" . '',
+ 'constants' => array(
+ ),
+ 'debugMethod' => '',
+ 'definition' => array(
+ 'extensionName' => false,
+ 'fileName' => false,
+ 'startLine' => false,
+ ),
+ 'extends' => array(
+ ),
+ 'implements' => array(
+ ),
+ 'interfacesCollapse' => array(
+ ),
+ 'isAbstract' => false,
+ 'isAnonymous' => false,
+ 'isExcluded' => false,
+ 'isFinal' => false,
+ 'isInterface' => false,
+ 'isLazy' => false,
+ 'isMaxDepth' => false,
+ 'isReadOnly' => false,
+ 'isRecursion' => false,
+ 'isTrait' => false,
+ 'keys' => array(
+ ),
+ 'methods' => array(
+ ),
+ 'methodsWithStaticVars' => array(
+ ),
+ 'phpDoc' => array(
+ 'desc' => '',
+ 'summary' => '',
+ ),
+ 'properties' => array(
+ ),
+ 'scopeClass' => null,
+ 'sectionOrder' => array(
+ 0 => 'attributes',
+ 1 => 'extends',
+ 2 => 'implements',
+ 3 => 'constants',
+ 4 => 'cases',
+ 5 => 'properties',
+ 6 => 'methods',
+ 7 => 'phpDoc',
+ ),
+ 'sort' => 'inheritance visibility name',
+ 'stringified' => null,
+ 'viaDebugInfo' => false,
+ ),
+ 'Simple' => array(
+ '__isUsed' => true,
+ 'className' => 'Simple',
+ 'debug' => \bdk\Debug\Abstraction\Abstracter::ABSTRACTION,
+ 'definition' => array(
+ 'fileName' => '/Users/bkent/Library/CloudStorage/Dropbox/git/bkdotcom/PHPDebugConsole/examples/serialize.php',
+ 'startLine' => 18,
+ ),
+ 'implements' => array(
+ 0 => 'Stringable',
+ ),
+ 'inheritsFrom' => '' . "\0" . 'default' . "\0" . '',
+ 'methods' => array(
+ '__toString' => array(
+ 'attributes' => array(
+ ),
+ 'declaredLast' => 'Simple',
+ 'declaredOrig' => 'Simple',
+ 'declaredPrev' => null,
+ 'implements' => 'Stringable',
+ 'isAbstract' => false,
+ 'isDeprecated' => false,
+ 'isFinal' => false,
+ 'isStatic' => false,
+ 'params' => array(
+ ),
+ 'phpDoc' => array(
+ 'desc' => '',
+ 'summary' => '',
+ ),
+ 'return' => array(
+ 'desc' => '',
+ 'type' => 'string',
+ ),
+ 'returnValue' => null,
+ 'staticVars' => array(
+ ),
+ 'visibility' => 'public',
+ ),
+ 'foo' => array(
+ 'attributes' => array(
+ ),
+ 'declaredLast' => 'Simple',
+ 'declaredOrig' => 'Simple',
+ 'declaredPrev' => null,
+ 'implements' => null,
+ 'isAbstract' => false,
+ 'isDeprecated' => false,
+ 'isFinal' => false,
+ 'isStatic' => false,
+ 'params' => array(
+ 0 => array(
+ 'attributes' => array(
+ ),
+ 'defaultValue' => \bdk\Debug\Abstraction\Abstracter::UNDEFINED,
+ 'desc' => 'the string you want to foo',
+ 'isOptional' => false,
+ 'isPassedByReference' => false,
+ 'isPromoted' => false,
+ 'isVariadic' => false,
+ 'name' => 'bar',
+ 'type' => 'string',
+ ),
+ ),
+ 'phpDoc' => array(
+ 'desc' => '',
+ 'summary' => 'Foo is a private method that does stuff',
+ ),
+ 'return' => array(
+ 'desc' => 'the fooed string',
+ 'type' => 'string',
+ ),
+ 'staticVars' => array(
+ ),
+ 'visibility' => 'private',
+ ),
+ ),
+ 'properties' => array(
+ 'offLimits' => array(
+ 'attributes' => array(
+ ),
+ 'debugInfoExcluded' => false,
+ 'declaredLast' => 'Simple',
+ 'declaredOrig' => 'Simple',
+ 'declaredPrev' => null,
+ 'forceShow' => false,
+ 'hooks' => array(
+ ),
+ 'isDeprecated' => false,
+ 'isFinal' => false,
+ 'isPromoted' => false,
+ 'isReadOnly' => false,
+ 'isStatic' => false,
+ 'isVirtual' => false,
+ 'phpDoc' => array(
+ 'desc' => '',
+ 'summary' => '',
+ ),
+ 'type' => null,
+ 'value' => 'I\'m a private property',
+ 'valueFrom' => 'value',
+ 'visibility' => array(
+ 0 => 'private',
+ ),
+ ),
+ ),
+ 'type' => 'object',
+ 'typeMore' => null,
+ ),
+ ),
+ 'config' => array(
+ 'channelIcon' => 'fa fa-list-ul',
+ 'channelKey' => 'general',
+ 'channelName' => 'general',
+ 'channels' => array(
+ 'php' => array(
+ 'channelIcon' => '🐘',
+ 'channelShow' => true,
+ 'channelSort' => 10,
+ 'nested' => false,
+ ),
+ ),
+ 'logRuntime' => true,
+ ),
+ 'log' => array(
+ 0 => array(
+ 0 => 'group',
+ 1 => array(
+ 0 => 'array o things',
+ ),
+ ),
+ 1 => array(
+ 0 => 'log',
+ 1 => array(
+ 0 => array(
+ 'boolean.true' => true,
+ 'boolean.false' => false,
+ 'int' => 7,
+ 'float' => 123.45,
+ 'null' => null,
+ 'object' => array(
+ 'debug' => \bdk\Debug\Abstraction\Abstracter::ABSTRACTION,
+ 'debugMethod' => 'log',
+ 'inheritsFrom' => 'Simple',
+ 'methods' => array(
+ '__toString' => array(
+ 'returnValue' => 'It\'s Magic',
+ ),
+ ),
+ 'type' => 'object',
+ ),
+ 'string' => 'Strings
+ get visual farts whitespace™ and control-char highlighting (hover over the highlights)',
+ 'string (numeric)' => '42',
+ 'string (timestamp)' => array(
+ 'brief' => false,
+ 'debug' => \bdk\Debug\Abstraction\Abstracter::ABSTRACTION,
+ 'type' => 'string',
+ 'typeMore' => 'timestamp',
+ 'value' => '1767270896',
+ ),
+ ),
+ ),
+ ),
+ 2 => array(
+ 0 => 'groupEnd',
+ 1 => array(
+ ),
+ ),
+ 3 => array(
+ 0 => 'table',
+ 1 => array(
+ 0 => array(
+ 'caption' => 'Populations',
+ 'debug' => \bdk\Debug\Abstraction\Abstracter::ABSTRACTION,
+ 'header' => array(
+ 0 => '',
+ 1 => 'city',
+ 2 => 'state',
+ 3 => 'population',
+ ),
+ 'meta' => array(
+ 'class' => null,
+ 'columns' => array(
+ 0 => array(
+ 'attribs' => array(
+ 'class' => array(
+ 0 => 't_key',
+ ),
+ 'scope' => 'row',
+ ),
+ 'key' => \bdk\Table\Factory::KEY_INDEX,
+ 'tagName' => 'th',
+ ),
+ 1 => array(
+ 'key' => 'city',
+ ),
+ 2 => array(
+ 'key' => 'state',
+ ),
+ 3 => array(
+ 'key' => 'population',
+ ),
+ ),
+ 'haveObjectRow' => false,
+ 'sortable' => true,
+ ),
+ 'rows' => array(
+ 0 => array(
+ 0 => 0,
+ 1 => 'Atlanta',
+ 2 => 'GA',
+ 3 => 472522,
+ ),
+ 1 => array(
+ 0 => 1,
+ 1 => 'Buffalo',
+ 2 => 'NY',
+ 3 => 256902,
+ ),
+ 2 => array(
+ 0 => 2,
+ 1 => 'Chicago',
+ 2 => 'IL',
+ 3 => 2704958,
+ ),
+ 3 => array(
+ 0 => 3,
+ 1 => 'Denver',
+ 2 => 'CO',
+ 3 => 693060,
+ ),
+ 4 => array(
+ 0 => 4,
+ 1 => 'Seattle',
+ 2 => 'WA',
+ 3 => 704352,
+ ),
+ 5 => array(
+ 0 => 5,
+ 1 => 'Tulsa',
+ 2 => 'OK',
+ 3 => 403090,
+ ),
+ ),
+ 'type' => 'table',
+ 'value' => null,
+ ),
+ ),
+ ),
+ ),
+ 'logSummary' => array(
+ 1 => array(
+ 0 => array(
+ 0 => 'info',
+ 1 => array(
+ 0 => 'Built in 123.123 ms',
+ ),
+ ),
+ 1 => array(
+ 0 => 'info',
+ 1 => array(
+ 0 => 'Peak memory usage...',
+ ),
+ 2 => array(
+ 'sanitize' => false,
+ ),
+ ),
+ ),
+ ),
+ 'requestId' => 'deadbeef',
+ 'runtime' => array(
+ 'memoryLimit' => '2G',
+ 'memoryPeakUsage' => '12123123',
+ 'runtime' => 0.123,
+ ),
+ 'version' => '3.6',
+);
diff --git a/tests/PubSub/Fixture/ValueStore.php b/tests/PubSub/Fixture/ValueStore.php
index 10bd7fe3..c276c7c1 100644
--- a/tests/PubSub/Fixture/ValueStore.php
+++ b/tests/PubSub/Fixture/ValueStore.php
@@ -18,7 +18,7 @@ protected function isGroovy()
return true;
}
- protected function onSet($values = array())
+ protected function onSet(array $values = array())
{
$this->onSetArgs[] = $values;
}
diff --git a/tests/Table/ElementTest.php b/tests/Table/ElementTest.php
new file mode 100644
index 00000000..63be1453
--- /dev/null
+++ b/tests/Table/ElementTest.php
@@ -0,0 +1,914 @@
+getTagName());
+ self::assertSame([], $element->getChildren());
+ self::assertSame('', $element->getHtml());
+ }
+
+ /**
+ * Test constructor with HTML content
+ */
+ public function testConstructorWithHtml()
+ {
+ $element = new Element('span', 'Hello World');
+ self::assertSame('span', $element->getTagName());
+ self::assertSame('Hello World', $element->getHtml());
+ }
+
+ /**
+ * Test constructor with children array
+ */
+ public function testConstructorWithChildren()
+ {
+ $child1 = new Element('span', 'Child 1');
+ $child2 = new Element('span', 'Child 2');
+ $element = new Element('div', [$child1, $child2]);
+
+ self::assertSame('div', $element->getTagName());
+ self::assertCount(2, $element->getChildren());
+ self::assertSame($element, $child1->getParent());
+ self::assertSame($element, $child2->getParent());
+ }
+
+ /**
+ * Test constructor with associative array of properties
+ */
+ public function testConstructorWithProperties()
+ {
+ $element = new Element('div', [
+ 'attribs' => ['class' => 'test-class', 'id' => 'test-id'],
+ 'html' => 'Test content',
+ 'meta' => ['key' => 'value'],
+ ]);
+
+ self::assertSame('div', $element->getTagName());
+ self::assertSame('Test content', $element->getHtml());
+ self::assertSame(['class' => ['test-class'], 'id' => 'test-id'], $element->getAttribs());
+ self::assertSame('value', $element->getMeta('key'));
+ }
+
+ /**
+ * Test setTagName / getTagName
+ */
+ public function testTagName()
+ {
+ $element = new Element('div');
+ self::assertSame('div', $element->getTagName());
+
+ $element->setTagName('SPAN');
+ self::assertSame('span', $element->getTagName());
+
+ $element->setTagName('TD');
+ self::assertSame('td', $element->getTagName());
+ }
+
+ /**
+ * Test setHtml / getHtml
+ */
+ public function testHtml()
+ {
+ $element = new Element('div');
+ self::assertSame('', $element->getHtml());
+
+ $element->setHtml('Bold');
+ self::assertSame('Bold', $element->getHtml());
+ }
+
+ /**
+ * Test setText / getText
+ */
+ public function testText()
+ {
+ $element = new Element('div');
+ $element->setText('Test & "quotes"');
+
+ self::assertSame('Test & "quotes"', $element->getHtml());
+ self::assertSame('Test & "quotes"', $element->getText());
+ }
+
+ /**
+ * Test getText with nested children
+ */
+ public function testGetTextWithChildren()
+ {
+ $child1 = new Element('span');
+ $child1->setText('Hello ');
+
+ $child2 = new Element('strong');
+ $child2->setText('World');
+
+ $parent = new Element('div', [$child1, $child2]);
+
+ self::assertSame('Hello World', $parent->getText());
+ }
+
+ /**
+ * Test setAttrib / getAttribs
+ */
+ public function testAttribs()
+ {
+ $element = new Element('div');
+
+ $element->setAttrib('id', 'test-id');
+ self::assertSame(['id' => 'test-id'], $element->getAttribs());
+
+ $element->setAttrib('data-value', '123');
+ self::assertSame([
+ 'data-value' => '123',
+ 'id' => 'test-id',
+ ], $element->getAttribs());
+ }
+
+ /**
+ * Test setAttribs (plural)
+ */
+ public function testSetAttribs()
+ {
+ $element = new Element('div');
+ $element->setAttribs([
+ 'id' => 'test-id',
+ 'class' => 'test-class',
+ 'data-value' => 'abc',
+ ]);
+
+ self::assertSame([
+ 'class' => ['test-class'],
+ 'data-value' => 'abc',
+ 'id' => 'test-id',
+ ], $element->getAttribs());
+ }
+
+ /**
+ * Test addClass
+ */
+ public function testAddClass()
+ {
+ $element = new Element('div');
+
+ $element->addClass('class1');
+ self::assertSame(['class' => ['class1']], $element->getAttribs());
+
+ $element->addClass('class2');
+ self::assertSame(['class' => ['class1', 'class2']], $element->getAttribs());
+
+ $element->addClass(['class3', 'class4']);
+ self::assertSame(['class' => ['class1', 'class2', 'class3', 'class4']], $element->getAttribs());
+
+ // Test duplicate class
+ $element->addClass('class1');
+ self::assertSame(['class' => ['class1', 'class2', 'class3', 'class4']], $element->getAttribs());
+ }
+
+ /**
+ * Test addClass with space-separated string
+ */
+ public function testAddClassWithSpaces()
+ {
+ $element = new Element('div');
+ $element->addClass('class1 class2 class3');
+
+ self::assertSame(['class' => ['class1', 'class2', 'class3']], $element->getAttribs());
+ }
+
+ /**
+ * Test addClass with array of classname => bool
+ */
+ public function testAddClassWithBooleanArray()
+ {
+ $element = new Element('div');
+
+ // Add classes conditionally based on boolean values
+ $element->addClass([
+ 'active' => true,
+ 'disabled' => false,
+ 'highlight' => true,
+ ]);
+
+ // Only classes with true values should be added
+ self::assertSame(['class' => ['active', 'highlight']], $element->getAttribs());
+
+ // Test with existing classes
+ $element->addClass([
+ 'disabled' => true,
+ 'active' => false, // Should remove active
+ ]);
+
+ // 'active' should be removed, 'disabled' added
+ self::assertSame(['class' => ['disabled', 'highlight']], $element->getAttribs());
+ }
+
+ /**
+ * Test addClass with mixed array (indexed and associative)
+ */
+ public function testAddClassWithMixedArray()
+ {
+ $element = new Element('div');
+ $element->addClass('existing');
+
+ // Mix of indexed (always add) and associative (conditional)
+ $element->addClass([
+ 'always-added',
+ 'conditional-true' => true,
+ 'conditional-false' => false,
+ ]);
+
+ self::assertSame(['class' => ['always-added', 'conditional-true', 'existing']], $element->getAttribs());
+ }
+
+ /**
+ * Test removeClass
+ */
+ public function testRemoveClass()
+ {
+ $element = new Element('div');
+ $element->addClass(['class1', 'class2', 'class3']);
+
+ $element->removeClass('class2');
+ self::assertSame(['class' => ['class1', 'class3']], $element->getAttribs());
+
+ $element->removeClass(['class1', 'class3']);
+ self::assertSame([], $element->getAttribs());
+ }
+
+ /**
+ * Test removeClass with space-separated string
+ */
+ public function testRemoveClassWithSpaces()
+ {
+ $element = new Element('div');
+ $element->addClass('class1 class2 class3');
+ $element->removeClass('class1 class3');
+
+ self::assertSame(['class' => ['class2']], $element->getAttribs());
+ }
+
+ /**
+ * Test appendChild
+ */
+ public function testAppendChild()
+ {
+ $parent = new Element('div');
+ $child1 = new Element('span', 'Child 1');
+ $child2 = new Element('span', 'Child 2');
+
+ $parent->appendChild($child1);
+ self::assertCount(1, $parent->getChildren());
+ self::assertSame($parent, $child1->getParent());
+
+ $parent->appendChild($child2);
+ self::assertCount(2, $parent->getChildren());
+ self::assertSame($parent, $child2->getParent());
+ }
+
+ /**
+ * Test setChildren
+ */
+ public function testSetChildren()
+ {
+ $parent = new Element('div');
+ $child1 = new Element('span', 'Child 1');
+ $child2 = new Element('span', 'Child 2');
+
+ $parent->setChildren([$child1, $child2]);
+
+ self::assertCount(2, $parent->getChildren());
+ self::assertSame($parent, $child1->getParent());
+ self::assertSame($parent, $child2->getParent());
+ }
+
+ /**
+ * Test setChildren with invalid child throws exception
+ */
+ public function testSetChildrenInvalid()
+ {
+ self::assertExceptionOrTypeError(function () {
+ $parent = new Element('div');
+ $parent->setChildren(['not an Element object']);
+ });
+ }
+
+ /**
+ * Test getChildren
+ */
+ public function testGetChildren()
+ {
+ $child1 = new Element('span', 'Child 1');
+ $child2 = new Element('span', 'Child 2');
+ $parent = new Element('div', [$child1, $child2]);
+
+ $children = $parent->getChildren();
+ self::assertCount(2, $children);
+ self::assertSame($child1, $children[0]);
+ self::assertSame($child2, $children[1]);
+ }
+
+ /**
+ * Test getHtml with children
+ */
+ public function testGetHtmlWithChildren()
+ {
+ $child1 = new Element('span', 'Child 1');
+ $child2 = new Element('strong', 'Child 2');
+ $parent = new Element('div', [$child1, $child2]);
+
+ $html = $parent->getHtml();
+ self::assertStringContainsString('Child 1', $html);
+ self::assertStringContainsString('Child 2', $html);
+ }
+
+ /**
+ * Test setParent / getParent
+ */
+ public function testParent()
+ {
+ $parent = new Element('div');
+ $child = new Element('span');
+
+ self::assertNull($child->getParent());
+
+ $child->setParent($parent);
+ self::assertSame($parent, $child->getParent());
+
+ $child->setParent(null);
+ self::assertNull($child->getParent());
+ }
+
+ /**
+ * Test setParent with invalid parent throws exception
+ */
+ public function testSetParentInvalid()
+ {
+ $this->expectException('InvalidArgumentException');
+ $this->expectExceptionMessage('Parent must be instance of');
+
+ $child = new Element('span');
+ $child->setParent('not an Element object');
+ }
+
+ /**
+ * Test getIndex
+ */
+ public function testGetIndex()
+ {
+ $parent = new Element('div');
+ $child1 = new Element('span', 'Child 1');
+ $child2 = new Element('span', 'Child 2');
+ $child3 = new Element('span', 'Child 3');
+
+ $parent->setChildren([$child1, $child2, $child3]);
+
+ self::assertSame(0, $child1->getIndex());
+ self::assertSame(1, $child2->getIndex());
+ self::assertSame(2, $child3->getIndex());
+ }
+
+ /**
+ * Test getIndex with no parent
+ */
+ public function testGetIndexNoParent()
+ {
+ $element = new Element('div');
+ self::assertNull($element->getIndex());
+ }
+
+ /**
+ * Test setMeta / getMeta
+ */
+ public function testMeta()
+ {
+ $element = new Element('div');
+
+ $element->setMeta('key1', 'value1');
+ self::assertSame('value1', $element->getMeta('key1'));
+
+ $element->setMeta('key2', 'value2');
+ self::assertSame('value2', $element->getMeta('key2'));
+
+ // Test getting non-existent key
+ self::assertNull($element->getMeta('nonexistent'));
+ self::assertSame('default', $element->getMeta('nonexistent', 'default'));
+ }
+
+ /**
+ * Test setMeta with array
+ */
+ public function testSetMetaArray()
+ {
+ $element = new Element('div');
+ $element->setMeta([
+ 'key1' => 'value1',
+ 'key2' => 'value2',
+ ]);
+
+ self::assertSame('value1', $element->getMeta('key1'));
+ self::assertSame('value2', $element->getMeta('key2'));
+ }
+
+ /**
+ * Test getMeta with no key returns all meta
+ */
+ public function testGetMetaAll()
+ {
+ $element = new Element('div');
+ $element->setMeta([
+ 'key1' => 'value1',
+ 'key2' => 'value2',
+ ]);
+
+ self::assertSame([
+ 'key1' => 'value1',
+ 'key2' => 'value2',
+ ], $element->getMeta());
+ }
+
+ /**
+ * Test setDefaults
+ */
+ public function testSetDefaults()
+ {
+ $element = new Element('div');
+ $element->setDefaults([
+ 'tagName' => 'div',
+ 'attribs' => ['class' => ['default-class']],
+ ]);
+
+ // Defaults should be merged with current attribs
+ $element->setAttrib('id', 'test-id');
+ self::assertSame([
+ 'class' => ['default-class'],
+ 'id' => 'test-id',
+ ], $element->getAttribs());
+ }
+
+ /**
+ * Test getOuterHtml
+ */
+ public function testGetOuterHtml()
+ {
+ $element = new Element('div', 'Hello World');
+ $element->setAttrib('id', 'test-id');
+ $element->setAttrib('class', 'test-class');
+
+ $html = $element->getOuterHtml();
+ self::assertSame('Hello World ', $html);
+ }
+
+ /**
+ * Test getOuterHtml with children
+ */
+ public function testGetOuterHtmlWithChildren()
+ {
+ $child1 = new Element('span', 'Child 1');
+ $child2 = new Element('strong', 'Child 2');
+ $parent = new Element('div', [$child1, $child2]);
+ $parent->setAttrib('id', 'parent');
+
+ $html = $parent->getOuterHtml();
+
+ self::assertStringContainsString('', $html);
+ self::assertStringContainsString('Child 1', $html);
+ self::assertStringContainsString('Child 2', $html);
+ self::assertStringContainsString(' ', $html);
+ }
+
+ /**
+ * Test __serialize
+ */
+ public function testSerialize()
+ {
+ $element = new Element('span', 'Test content');
+ $element->setAttrib('id', 'test-id');
+ $element->setMeta('key', 'value');
+
+ $data = $element->__serialize();
+
+ // tagName should be in data since it's different from default 'div'
+ self::assertArrayHasKey('tagName', $data);
+ self::assertArrayHasKey('html', $data);
+ self::assertArrayHasKey('attribs', $data);
+ self::assertArrayHasKey('meta', $data);
+ self::assertSame('span', $data['tagName']);
+ self::assertSame('Test content', $data['html']);
+ self::assertSame(['id' => 'test-id'], $data['attribs']);
+ self::assertSame(['key' => 'value'], $data['meta']);
+ }
+
+ /**
+ * Test __serialize with children
+ */
+ public function testSerializeWithChildren()
+ {
+ $child1 = new Element('span', 'Child 1');
+ $child2 = new Element('strong', 'Child 2');
+ $parent = new Element('div', [$child1, $child2]);
+
+ $data = $parent->__serialize();
+
+ self::assertArrayHasKey('children', $data);
+ self::assertCount(2, $data['children']);
+ }
+
+ /**
+ * Test __unserialize
+ */
+ public function testUnserialize()
+ {
+ $element = new Element('span');
+ $element->__unserialize([
+ 'tagName' => 'div',
+ 'html' => 'Test content',
+ 'attribs' => ['id' => 'test-id'],
+ 'meta' => ['key' => 'value'],
+ ]);
+
+ self::assertSame('div', $element->getTagName());
+ self::assertSame('Test content', $element->getHtml());
+ self::assertSame(['id' => 'test-id'], $element->getAttribs());
+ self::assertSame('value', $element->getMeta('key'));
+ }
+
+ /**
+ * Test serialize / unserialize methods (Serializable interface)
+ */
+ public function testSerializableMethods()
+ {
+ $element = new Element('span', 'Test content');
+ $element->setAttrib('id', 'test-id');
+ $element->setMeta('key', 'value');
+
+ $serialized = $element->serialize();
+ self::assertIsString($serialized);
+
+ $newElement = new Element('div');
+ $newElement->unserialize($serialized);
+
+ self::assertSame('span', $newElement->getTagName());
+ self::assertSame('Test content', $newElement->getHtml());
+ self::assertSame(['id' => 'test-id'], $newElement->getAttribs());
+ self::assertSame('value', $newElement->getMeta('key'));
+ }
+
+ /**
+ * Test jsonSerialize
+ */
+ public function testJsonSerialize()
+ {
+ $element = new Element('span', 'Test content');
+ $element->setAttrib('id', 'test-id');
+
+ $json = $element->jsonSerialize();
+
+ self::assertIsArray($json);
+ self::assertArrayHasKey('tagName', $json);
+ self::assertArrayHasKey('html', $json);
+ self::assertArrayHasKey('attribs', $json);
+ }
+
+ /**
+ * Test jsonSerialize with only HTML returns string
+ */
+ public function testJsonSerializeHtmlOnly()
+ {
+ $element = new Element('div', 'Test content');
+
+ $json = $element->jsonSerialize();
+
+ self::assertSame('Test content', $json);
+ }
+
+ /**
+ * Test jsonSerialize with only children returns array
+ */
+ public function testJsonSerializeChildrenOnly()
+ {
+ $child1 = new Element('span', 'Child 1');
+ $child2 = new Element('strong', 'Child 2');
+ $parent = new Element('div', [$child1, $child2]);
+
+ $json = $parent->jsonSerialize();
+
+ self::assertIsArray($json);
+ self::assertCount(2, $json);
+ }
+
+ /**
+ * Test that empty values are not serialized
+ */
+ public function testSerializeEmptyValues()
+ {
+ $element = new Element('span');
+
+ $data = $element->__serialize();
+
+ // Empty arrays and nulls should not be included, but tagName differs from default
+ self::assertArrayHasKey('tagName', $data);
+ self::assertSame('span', $data['tagName']);
+ // html is empty string which gets filtered out
+ self::assertArrayNotHasKey('attribs', $data);
+ self::assertArrayNotHasKey('meta', $data);
+ self::assertArrayNotHasKey('children', $data);
+ }
+
+ /**
+ * Test that default values are not serialized
+ */
+ public function testSerializeDefaultValues()
+ {
+ $element = new Element('div');
+ $element->setDefaults([
+ 'tagName' => 'div',
+ 'attribs' => ['class' => ['default-class']],
+ ]);
+
+ $data = $element->__serialize();
+
+ // Default tagName should not be in serialized data
+ self::assertArrayNotHasKey('tagName', $data);
+ }
+
+ /**
+ * Test fluent interface (chaining)
+ */
+ public function testFluentInterface()
+ {
+ $element = new Element('div');
+
+ $result = $element
+ ->setTagName('span')
+ ->setHtml('Test')
+ ->setAttrib('id', 'test-id')
+ ->addClass('test-class')
+ ->setMeta('key', 'value');
+
+ self::assertSame($element, $result);
+ self::assertSame('span', $element->getTagName());
+ self::assertSame('Test', $element->getHtml());
+ self::assertSame([
+ 'class' => ['test-class'],
+ 'id' => 'test-id',
+ ], $element->getAttribs());
+ self::assertSame('value', $element->getMeta('key'));
+ }
+
+ /**
+ * Test complex nested structure
+ */
+ public function testComplexNestedStructure()
+ {
+ $grandchild1 = new Element('em', 'Emphasized');
+ $grandchild2 = new Element('strong', 'Bold');
+
+ $child1 = new Element('span', [$grandchild1]);
+ $child1->setAttrib('class', 'child-span');
+
+ $child2 = new Element('div', [$grandchild2]);
+ $child2->setAttrib('id', 'child-div');
+
+ $parent = new Element('article', [$child1, $child2]);
+ $parent->setAttrib('class', 'parent-article');
+
+ // Test structure
+ self::assertSame($parent, $child1->getParent());
+ self::assertSame($parent, $child2->getParent());
+ self::assertSame($child1, $grandchild1->getParent());
+ self::assertSame($child2, $grandchild2->getParent());
+
+ // Test HTML generation
+ $html = $parent->getOuterHtml();
+ self::assertStringContainsString('', $html);
+ self::assertStringContainsString('', $html);
+ self::assertStringContainsString('', $html);
+ self::assertStringContainsString('Emphasized', $html);
+ self::assertStringContainsString('Bold', $html);
+ }
+
+ /**
+ * Test setting and getting empty class attribute
+ */
+ public function testEmptyClassAttribute()
+ {
+ $element = new Element('div');
+ $element->setAttrib('class', []);
+
+ // Empty class should not be in attributes
+ self::assertSame([], $element->getAttribs());
+ }
+
+ /**
+ * Test class normalization with duplicates and empty strings
+ */
+ public function testClassNormalization()
+ {
+ $element = new Element('div');
+ $element->addClass(['class1', '', 'class2', 'class1', 'class3', '']);
+
+ // Should filter out empty strings and duplicates, and sort
+ self::assertSame(['class' => ['class1', 'class2', 'class3']], $element->getAttribs());
+ }
+
+ /**
+ * Test unserialize with invalid data
+ */
+ public function testUnserializeWithInvalidData()
+ {
+ $element = new Element('div', 'Original');
+
+ // Unserialize with non-array should not change element
+ $element->unserialize(\serialize('not an array'));
+
+ self::assertSame('div', $element->getTagName());
+ self::assertSame('Original', $element->getHtml());
+ }
+
+ /**
+ * Test constructor with empty associative array
+ */
+ public function testConstructorWithEmptyAssociativeArray()
+ {
+ $element = new Element('div', []);
+
+ self::assertSame('div', $element->getTagName());
+ self::assertSame([], $element->getChildren());
+ }
+
+ /**
+ * Test getAttribs with defaults
+ */
+ public function testGetAttribsWithDefaults()
+ {
+ $element = new Element('div');
+ $element->setDefaults([
+ 'attribs' => [
+ 'class' => ['default-class'],
+ 'data-default' => 'value',
+ ],
+ ]);
+
+ $element->setAttrib('id', 'test-id');
+ $element->addClass('custom-class');
+
+ $attribs = $element->getAttribs();
+
+ // Defaults should be merged with custom attributes
+ self::assertArrayHasKey('class', $attribs);
+ self::assertContains('default-class', $attribs['class']);
+ self::assertContains('custom-class', $attribs['class']);
+ self::assertSame('value', $attribs['data-default']);
+ self::assertSame('test-id', $attribs['id']);
+ }
+
+ /**
+ * Test getText with HTML entities
+ */
+ public function testGetTextWithHtmlEntities()
+ {
+ $element = new Element('div');
+ $element->setHtml('Test <tag> & "quotes"');
+
+ // getText should decode HTML entities
+ self::assertSame('Test & "quotes"', $element->getText());
+ }
+
+ /**
+ * Test getText with nested HTML tags
+ */
+ public function testGetTextWithNestedTags()
+ {
+ $element = new Element('div');
+ $element->setHtml('Bold and italic text');
+
+ // getText should strip all tags
+ self::assertSame('Bold and italic text', $element->getText());
+ }
+
+ /**
+ * Test serialization of nested children
+ */
+ public function testSerializeNestedChildren()
+ {
+ $grandchild = new Element('em', 'Nested');
+ $child = new Element('span', [$grandchild]);
+ $parent = new Element('div', [$child]);
+
+ $data = $parent->__serialize();
+
+ self::assertArrayHasKey('children', $data);
+ self::assertIsArray($data['children']);
+ self::assertCount(1, $data['children']);
+ }
+
+ /**
+ * Test that addClass returns the element for chaining
+ */
+ public function testAddClassReturnsElement()
+ {
+ $element = new Element('div');
+ $result = $element->addClass('test-class');
+
+ self::assertSame($element, $result);
+ }
+
+ /**
+ * Test that removeClass returns the element for chaining
+ */
+ public function testRemoveClassReturnsElement()
+ {
+ $element = new Element('div');
+ $element->addClass('test-class');
+ $result = $element->removeClass('test-class');
+
+ self::assertSame($element, $result);
+ }
+
+ /**
+ * Test that appendChild returns the element for chaining
+ */
+ public function testAppendChildReturnsElement()
+ {
+ $parent = new Element('div');
+ $child = new Element('span');
+ $result = $parent->appendChild($child);
+
+ self::assertSame($parent, $result);
+ }
+
+ /**
+ * Test empty HTML string
+ */
+ public function testEmptyHtmlString()
+ {
+ $element = new Element('div', '');
+
+ self::assertSame('', $element->getHtml());
+ self::assertSame('', $element->getText());
+ }
+
+ /**
+ * Test getHtml with both children and HTML set
+ */
+ public function testGetHtmlPrioritizesChildren()
+ {
+ $child = new Element('span', 'Child');
+ $parent = new Element('div', [$child]);
+
+ // Setting HTML doesn't affect children
+ $parent->setHtml('New HTML content');
+
+ // Children still exist
+ self::assertCount(1, $parent->getChildren());
+
+ // getHtml returns children HTML when children exist, not the set HTML
+ $html = $parent->getHtml();
+ self::assertStringContainsString('Child', $html);
+ }
+
+ protected static function assertExceptionOrTypeError($callable)
+ {
+ try {
+ $callable();
+ } catch (ErrorException $e) {
+ // self::assertSame('A non well formed numeric value encountered', $e->getMessage());
+ self::assertTrue(true);
+ return;
+ } catch (RuntimeException $e) {
+ // self::assertSame('A non well formed numeric value encountered', $e->getMessage());
+ self::assertTrue(true);
+ return;
+ } catch (InvalidArgumentException $e) {
+ self::assertTrue(true);
+ return;
+ } catch (TypeError $e) {
+ self::assertSame(\get_class($e), 'TypeError');
+ return;
+ }
+ throw new AssertionFailedError('Exception not thrown');
+ }
+}
diff --git a/tests/Table/FactoryTest.php b/tests/Table/FactoryTest.php
new file mode 100644
index 00000000..f5c3d95e
--- /dev/null
+++ b/tests/Table/FactoryTest.php
@@ -0,0 +1,791 @@
+ 'John', 'age' => 30],
+ ['name' => 'Jane', 'age' => 25],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ self::assertCount(2, $table->getRows());
+ }
+
+ /**
+ * Test create with empty array
+ */
+ public function testCreateWithEmptyArray()
+ {
+ $factory = new Factory();
+ $table = $factory->create([]);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ self::assertCount(0, $table->getRows());
+ }
+
+ /**
+ * Test create with indexed array
+ */
+ public function testCreateWithIndexedArray()
+ {
+ $factory = new Factory();
+ $data = [
+ ['Apple', 'Red'],
+ ['Banana', 'Yellow'],
+ ['Orange', 'Orange'],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertCount(3, $table->getRows());
+ }
+
+ /**
+ * Test create with objects
+ */
+ public function testCreateWithObjects()
+ {
+ $factory = new Factory();
+
+ $obj1 = new stdClass();
+ $obj1->name = 'Item 1';
+ $obj1->price = 10.50;
+
+ $obj2 = new stdClass();
+ $obj2->name = 'Item 2';
+ $obj2->price = 20.75;
+
+ $data = [$obj1, $obj2];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ self::assertCount(2, $table->getRows());
+ }
+
+ /**
+ * Test create with object as data source
+ */
+ public function testCreateWithObjectAsData()
+ {
+ $factory = new Factory();
+
+ $data = new stdClass();
+ $data->item1 = ['name' => 'Item 1', 'value' => 100];
+ $data->item2 = ['name' => 'Item 2', 'value' => 200];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ self::assertCount(2, $table->getRows());
+ }
+
+ /**
+ * Test create with scalar values
+ */
+ public function testCreateWithScalarValues()
+ {
+ $factory = new Factory();
+ $data = [10, true, false, null, 'string'];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ self::assertCount(5, $table->getRows());
+ }
+
+ /**
+ * Test create with mixed array structures
+ */
+ public function testCreateWithMixedArrays()
+ {
+ $factory = new Factory();
+ $data = [
+ ['a' => 1, 'b' => 2],
+ ['a' => 3, 'c' => 4],
+ ['b' => 5, 'c' => 6],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertCount(3, $table->getRows());
+ // Should have columns for index, a, b, c
+ $header = $table->getHeader();
+ self::assertInstanceOf(self::CLASS_TABLE_ROW, $header);
+ }
+
+ /**
+ * Test column ordering with inconsistent keys
+ */
+ public function testColumnOrderingWithInconsistentKeys()
+ {
+ $factory = new Factory();
+ $data = [
+ ['name' => 'John', 'age' => 30, 'city' => 'NYC'],
+ ['name' => 'Jane', 'city' => 'LA', 'state' => 'CA'],
+ ['age' => 25, 'name' => 'Bob', 'state' => 'TX'],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertCount(3, $table->getRows());
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ }
+
+ /**
+ * Test with column labels option
+ */
+ public function testCreateWithColumnLabels()
+ {
+ $factory = new Factory();
+ $data = [
+ ['name' => 'John', 'age' => 30],
+ ['name' => 'Jane', 'age' => 25],
+ ];
+
+ $options = [
+ 'columnLabels' => [
+ 'age' => 'Age (years)',
+ 'name' => 'Full Name',
+ ],
+ ];
+
+ $table = $factory->create($data, $options);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ $header = $table->getHeader();
+ self::assertInstanceOf(self::CLASS_TABLE_ROW, $header);
+ }
+
+ /**
+ * Test with columns option (specify columns)
+ */
+ public function testCreateWithColumnsOption()
+ {
+ $factory = new Factory();
+ $data = [
+ ['name' => 'John', 'age' => 30, 'city' => 'NYC'],
+ ['name' => 'Jane', 'age' => 25, 'city' => 'LA'],
+ ];
+
+ $options = [
+ 'columns' => ['name', 'age'],
+ ];
+
+ $table = $factory->create($data, $options);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ // Should only have index, name, and age columns
+ $header = $table->getHeader();
+ self::assertInstanceOf(self::CLASS_TABLE_ROW, $header);
+ $cells = $header->getCells();
+ self::assertCount(3, $cells); // index, name, age
+ }
+
+ /**
+ * Test with totalCols option
+ */
+ public function testCreateWithTotalCols()
+ {
+ $factory = new Factory();
+ $data = [
+ ['product' => 'A', 'quantity' => 10, 'price' => 5.50],
+ ['product' => 'B', 'quantity' => 20, 'price' => 3.25],
+ ['product' => 'C', 'quantity' => 15, 'price' => 7.00],
+ ];
+
+ $options = [
+ 'totalCols' => ['quantity', 'price'],
+ ];
+
+ $table = $factory->create($data, $options);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+
+ // Should have footer with totals
+ $footer = $table->getFooter();
+ self::assertInstanceOf(self::CLASS_TABLE_ROW, $footer);
+ }
+
+ /**
+ * Test constructor with default options
+ */
+ public function testConstructorWithDefaultOptions()
+ {
+ $defaultOptions = [
+ 'columnLabels' => [
+ 'id' => 'ID',
+ 'name' => 'Name',
+ ],
+ ];
+
+ $factory = new Factory($defaultOptions);
+
+ $data = [
+ ['id' => 1, 'name' => 'Item 1'],
+ ['id' => 2, 'name' => 'Item 2'],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ }
+
+ /**
+ * Test that options are merged correctly
+ */
+ public function testOptionsAreMerged()
+ {
+ $defaultOptions = [
+ 'columnLabels' => [
+ 'id' => 'ID',
+ ],
+ ];
+
+ $factory = new Factory($defaultOptions);
+
+ $createOptions = [
+ 'columnLabels' => [
+ 'name' => 'Name',
+ ],
+ ];
+
+ $data = [
+ ['id' => 1, 'name' => 'Item'],
+ ];
+
+ $table = $factory->create($data, $createOptions);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ }
+
+ /**
+ * Test header is created
+ */
+ public function testHeaderIsCreated()
+ {
+ $factory = new Factory();
+ $data = [
+ ['col1' => 'A', 'col2' => 'B'],
+ ];
+
+ $table = $factory->create($data);
+
+ $header = $table->getHeader();
+ self::assertInstanceOf(self::CLASS_TABLE_ROW, $header);
+
+ $cells = $header->getCells();
+ self::assertGreaterThan(0, \count($cells));
+ }
+
+ /**
+ * Test footer is created with totals
+ */
+ public function testFooterIsCreatedWithTotals()
+ {
+ $factory = new Factory();
+ $data = [
+ ['value' => 10],
+ ['value' => 20],
+ ['value' => 30],
+ ];
+
+ $table = $factory->create($data, ['totalCols' => ['value']]);
+
+ $footer = $table->getFooter();
+ self::assertInstanceOf(self::CLASS_TABLE_ROW, $footer);
+ }
+
+ /**
+ * Test no footer when totalCols is empty
+ */
+ public function testNoFooterWhenTotalColsEmpty()
+ {
+ $factory = new Factory();
+ $data = [
+ ['value' => 10],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertNull($table->getFooter());
+ }
+
+ /**
+ * Test meta information is set
+ */
+ public function testMetaInformationIsSet()
+ {
+ $factory = new Factory();
+ $data = [
+ ['name' => 'Item'],
+ ];
+
+ $table = $factory->create($data);
+
+ $meta = $table->getMeta();
+ self::assertIsArray($meta);
+ self::assertArrayHasKey('columns', $meta);
+ }
+
+ /**
+ * Test meta class is set when data is object
+ */
+ public function testMetaClassIsSetWhenDataIsObject()
+ {
+ $factory = new Factory();
+
+ $data = new stdClass();
+ $data->item1 = ['value' => 1];
+
+ $table = $factory->create($data);
+
+ $meta = $table->getMeta();
+ self::assertSame('stdClass', $meta['class']);
+ }
+
+ /**
+ * Test KEY_INDEX column has proper cell attributes
+ */
+ public function testKeyIndexColumnHasProperAttributes()
+ {
+ $factory = new Factory();
+ $data = [
+ ['value' => 1],
+ ];
+
+ $table = $factory->create($data);
+
+ $meta = $table->getMeta();
+ $rows = $table->getRows();
+ $firstRow = $rows[0];
+ $cells = $firstRow->getCells();
+ $firstCell = $cells[0];
+
+ // First cell should be the index column
+ self::assertSame('td', $firstCell->getTagName());
+ self::assertSame('th', $meta['columns'][0]['tagName']);
+ self::assertContains('t_key', $meta['columns'][0]['attribs']['class']);
+ self::assertSame('row', $meta['columns'][0]['attribs']['scope']);
+ self::assertSame('| 0 | ', $firstCell->getOuterHtml());
+ }
+
+ /**
+ * Test VAL_UNDEFINED constant
+ */
+ public function testValUndefinedConstant()
+ {
+ self::assertIsString(Factory::VAL_UNDEFINED);
+ self::assertNotEmpty(Factory::VAL_UNDEFINED);
+ }
+
+ /**
+ * Test KEY_CLASS_NAME constant
+ */
+ public function testKeyClassNameConstant()
+ {
+ self::assertSame('___class_name', Factory::KEY_CLASS_NAME);
+ }
+
+ /**
+ * Test KEY_INDEX constant
+ */
+ public function testKeyIndexConstant()
+ {
+ self::assertIsString(Factory::KEY_INDEX);
+ }
+
+ /**
+ * Test KEY_SCALAR constant
+ */
+ public function testKeyScalarConstant()
+ {
+ self::assertIsString(Factory::KEY_SCALAR);
+ }
+
+ /**
+ * Test with null values
+ */
+ public function testCreateWithNullValues()
+ {
+ $factory = new Factory();
+ $data = [
+ ['name' => 'John', 'age' => null],
+ ['name' => null, 'age' => 25],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ self::assertCount(2, $table->getRows());
+ }
+
+ /**
+ * Test with boolean values
+ */
+ public function testCreateWithBooleanValues()
+ {
+ $factory = new Factory();
+ $data = [
+ ['active' => true, 'visible' => false],
+ ['active' => false, 'visible' => true],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ self::assertCount(2, $table->getRows());
+ }
+
+ /**
+ * Test with numeric keys
+ */
+ public function testCreateWithNumericKeys()
+ {
+ $factory = new Factory();
+ $data = [
+ [10 => 'A', 20 => 'B'],
+ [10 => 'C', 20 => 'D'],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ }
+
+ /**
+ * Test column meta with objects of same class
+ */
+ public function testColumnMetaWithObjectsOfSameClass()
+ {
+ $factory = new Factory();
+
+ $obj1 = new stdClass();
+ $obj1->value = 1;
+
+ $obj2 = new stdClass();
+ $obj2->value = 2;
+
+ $data = [
+ ['object' => $obj1],
+ ['object' => $obj2],
+ ];
+
+ $table = $factory->create($data);
+
+ $meta = $table->getMeta();
+ // Column meta should track that all values are stdClass
+ self::assertIsArray($meta['columns']);
+ }
+
+ /**
+ * Test with nested arrays
+ */
+ public function testCreateWithNestedArrays()
+ {
+ $factory = new Factory();
+ $data = [
+ ['name' => 'Item', 'details' => ['color' => 'red', 'size' => 'large']],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ }
+
+ /**
+ * Test totals calculation
+ */
+ public function testTotalsCalculation()
+ {
+ $factory = new Factory();
+ $data = [
+ ['qty' => 10, 'price' => 5.50],
+ ['qty' => 20, 'price' => 3.25],
+ ['qty' => 15, 'price' => 7.00],
+ ];
+
+ $table = $factory->create($data, ['totalCols' => ['qty', 'price']]);
+
+ $footer = $table->getFooter();
+ self::assertInstanceOf(self::CLASS_TABLE_ROW, $footer);
+
+ $cells = $footer->getCells();
+ // Check that totals were calculated (45 for qty, 15.75 for price)
+ self::assertGreaterThan(0, \count($cells));
+ }
+
+ /**
+ * Test totals ignore non-numeric values
+ */
+ public function testTotalsIgnoreNonNumericValues()
+ {
+ $factory = new Factory();
+ $data = [
+ ['value' => 10],
+ ['value' => 'text'],
+ ['value' => 20],
+ ];
+
+ $table = $factory->create($data, ['totalCols' => ['value']]);
+
+ $footer = $table->getFooter();
+ self::assertInstanceOf(self::CLASS_TABLE_ROW, $footer);
+ }
+
+ /**
+ * Test empty string values
+ */
+ public function testCreateWithEmptyStrings()
+ {
+ $factory = new Factory();
+ $data = [
+ ['name' => '', 'value' => 0],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ }
+
+ /**
+ * Test with single row
+ */
+ public function testCreateWithSingleRow()
+ {
+ $factory = new Factory();
+ $data = [
+ ['only' => 'row'],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertCount(1, $table->getRows());
+ }
+
+ /**
+ * Test with many rows
+ */
+ public function testCreateWithManyRows()
+ {
+ $factory = new Factory();
+ $data = [];
+
+ for ($i = 0; $i < 100; $i++) {
+ $data[] = ['index' => $i, 'value' => $i * 2];
+ }
+
+ $table = $factory->create($data);
+
+ self::assertCount(100, $table->getRows());
+ }
+
+ /**
+ * Test multiple create calls with same factory
+ */
+ public function testMultipleCreateCalls()
+ {
+ $factory = new Factory();
+
+ $data1 = [['a' => 1]];
+ $table1 = $factory->create($data1);
+
+ $data2 = [['b' => 2]];
+ $table2 = $factory->create($data2);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table1);
+ self::assertInstanceOf(self::CLASS_TABLE, $table2);
+ self::assertNotSame($table1, $table2);
+ }
+
+ /**
+ * Test with object having properties
+ */
+ public function testCreateWithObjectHavingProperties()
+ {
+ $factory = new Factory();
+
+ $obj = (object) array(
+ 'foo' => 'bar',
+ );
+
+ $data = [$obj];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ }
+
+ /**
+ * Test with DateTime objects
+ */
+ public function testCreateWithDateTimeObjects()
+ {
+ $factory = new Factory();
+ $data = [
+ ['date' => new \DateTime('2025-01-01')],
+ ['date' => new \DateTime('2025-12-31')],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ }
+
+ /**
+ * Test column labels for special keys
+ */
+ public function testColumnLabelsForSpecialKeys()
+ {
+ $factory = new Factory([
+ 'columnLabels' => [
+ Factory::KEY_INDEX => 'Index',
+ Factory::KEY_SCALAR => 'Value',
+ ],
+ ]);
+
+ $data = [1, 2, 3];
+
+ $table = $factory->create($data);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ }
+
+ /**
+ * Test with associative array having string keys
+ */
+ public function testCreateWithAssociativeArrayStringKeys()
+ {
+ $factory = new Factory();
+ $data = [
+ 'first' => ['name' => 'First'],
+ 'second' => ['name' => 'Second'],
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertCount(2, $table->getRows());
+ }
+
+ /**
+ * Test that undefined values are handled
+ */
+ public function testUndefinedValuesAreHandled()
+ {
+ $factory = new Factory();
+ $data = [
+ ['a' => 1, 'b' => 2],
+ ['a' => 3], // 'b' is undefined
+ ];
+
+ $table = $factory->create($data);
+
+ self::assertCount(2, $table->getRows());
+ }
+
+ /**
+ * Test with object missing specified columns
+ */
+ public function testWithObjectMissingSpecifiedColumns()
+ {
+ $factory = new Factory();
+
+ $obj = new stdClass();
+ $obj->existing = 'value';
+
+ $data = [$obj];
+ $options = ['columns' => ['existing', 'nonexistent']];
+
+ $table = $factory->create($data, $options);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+ }
+
+ /**
+ * Test column consistency across rows
+ */
+ public function testColumnConsistencyAcrossRows()
+ {
+ $factory = new Factory();
+ $data = [
+ ['a' => 1],
+ ['b' => 2],
+ ['c' => 3],
+ ];
+
+ $table = $factory->create($data);
+
+ // Each row should have same number of cells (including undefined values)
+ $rows = $table->getRows();
+ $cellCount = \count($rows[0]->getCells());
+
+ foreach ($rows as $row) {
+ self::assertCount($cellCount, $row->getCells());
+ }
+ }
+
+ /**
+ * Test inclIndex = false option excludes index column
+ */
+ public function testInclIndexFalse()
+ {
+ $factory = new Factory();
+ $data = [
+ ['name' => 'John', 'age' => 30],
+ ['name' => 'Jane', 'age' => 25],
+ ];
+
+ $table = $factory->create($data, ['inclIndex' => false]);
+
+ self::assertInstanceOf(self::CLASS_TABLE, $table);
+
+ // Check header cells - should not include index column
+ $header = $table->getHeader();
+ $headerCells = $header->getCells();
+ self::assertCount(2, $headerCells); // Only 'name' and 'age'
+
+ // Check that first cell is not an index column
+ $firstCell = $headerCells[0];
+ self::assertNotEquals('', $firstCell->getValue()); // Index column label is empty string by default
+
+ // Check row cells - should also not include index column
+ $rows = $table->getRows();
+ self::assertCount(2, $rows);
+
+ foreach ($rows as $row) {
+ $cells = $row->getCells();
+ self::assertCount(2, $cells); // Only 'name' and 'age' columns
+ }
+
+ // Verify meta columns don't include KEY_INDEX
+ $meta = $table->getMeta();
+ $columnKeys = \array_column($meta['columns'], 'key');
+ self::assertNotContains(Factory::KEY_INDEX, $columnKeys);
+ }
+}
+
diff --git a/tests/Table/Fixture/Stringable.php b/tests/Table/Fixture/Stringable.php
new file mode 100644
index 00000000..689bd9f8
--- /dev/null
+++ b/tests/Table/Fixture/Stringable.php
@@ -0,0 +1,18 @@
+message = $message;
+ }
+
+ public function __toString()
+ {
+ return $this->message;
+ }
+}
diff --git a/tests/Table/TableCellTest.php b/tests/Table/TableCellTest.php
new file mode 100644
index 00000000..222a2bdb
--- /dev/null
+++ b/tests/Table/TableCellTest.php
@@ -0,0 +1,728 @@
+getProperty('valDumper');
+ if (PHP_VERSION_ID < 80100) {
+ $property->setAccessible(true);
+ }
+ self::$originalValDumper = $property->getValue();
+ }
+
+ /**
+ * Tear down after each test
+ */
+ public function tearDown(): void
+ {
+ parent::tearDown();
+ // Restore original dumper
+ TableCell::setValDumper(self::$originalValDumper);
+ }
+
+ /**
+ * Test basic constructor
+ */
+ public function testConstructorBasic()
+ {
+ $cell = new TableCell();
+
+ self::assertSame('td', $cell->getTagName());
+ self::assertNull($cell->getValue());
+ }
+
+ /**
+ * Test constructor with string value
+ */
+ public function testConstructorWithString()
+ {
+ $cell = new TableCell('Test Value');
+
+ self::assertSame('Test Value', $cell->getValue());
+ self::assertSame('td', $cell->getTagName());
+ }
+
+ /**
+ * Test constructor with integer value
+ */
+ public function testConstructorWithInteger()
+ {
+ $cell = new TableCell(42);
+
+ self::assertSame(42, $cell->getValue());
+ }
+
+ /**
+ * Test constructor with float value
+ */
+ public function testConstructorWithFloat()
+ {
+ $cell = new TableCell(3.14);
+
+ self::assertSame(3.14, $cell->getValue());
+ }
+
+ /**
+ * Test constructor with boolean value
+ */
+ public function testConstructorWithBoolean()
+ {
+ $cell = new TableCell(true);
+
+ self::assertTrue($cell->getValue());
+ }
+
+ /**
+ * Test constructor with null value
+ */
+ public function testConstructorWithNull()
+ {
+ $cell = new TableCell(null);
+
+ self::assertNull($cell->getValue());
+ }
+
+ /**
+ * Test constructor with array value
+ */
+ public function testConstructorWithArrayValue()
+ {
+ $cell = new TableCell(['a', 'b', 'c']);
+
+ self::assertSame(['a', 'b', 'c'], $cell->getValue());
+ }
+
+ /**
+ * Test constructor with associative array (properties)
+ */
+ public function testConstructorWithProperties()
+ {
+ $cell = new TableCell([
+ 'attribs' => ['class' => 'highlight'],
+ 'tagName' => 'th',
+ 'value' => 'Test',
+ ]);
+
+ self::assertSame('Test', $cell->getValue());
+ self::assertSame(['class' => ['highlight']], $cell->getAttribs());
+ self::assertSame('th', $cell->getTagName());
+ }
+
+ /**
+ * Test getValue
+ */
+ public function testGetValue()
+ {
+ $cell = new TableCell('My Value');
+
+ self::assertSame('My Value', $cell->getValue());
+ }
+
+ /**
+ * Test setValue
+ */
+ public function testSetValue()
+ {
+ $cell = new TableCell();
+
+ $result = $cell->setValue('New Value');
+
+ self::assertSame($cell, $result);
+ self::assertSame('New Value', $cell->getValue());
+ }
+
+ /**
+ * Test setValue with different types
+ */
+ public function testSetValueDifferentTypes()
+ {
+ $cell = new TableCell();
+
+ $cell->setValue(100);
+ self::assertSame(100, $cell->getValue());
+
+ $cell->setValue(true);
+ self::assertTrue($cell->getValue());
+
+ $cell->setValue(['array']);
+ self::assertSame(['array'], $cell->getValue());
+ }
+
+ /**
+ * Test getHtml with explicit HTML set
+ */
+ public function testGetHtmlWithExplicitHtml()
+ {
+ $cell = new TableCell('value');
+ $cell->setHtml('Bold');
+
+ $html = $cell->getHtml();
+
+ self::assertSame('Bold', $html);
+ }
+
+ /**
+ * Test getHtml with value dumper (default)
+ */
+ public function testGetHtmlWithValueDumper()
+ {
+ $cell = new TableCell('Test String');
+
+ $html = $cell->getHtml();
+
+ self::assertStringContainsString('Test String', $html);
+ // Default dumper adds class
+ self::assertArrayHasKey('class', $cell->getAttribs());
+ }
+
+ /**
+ * Test getHtml with string value
+ */
+ public function testGetHtmlStringValue()
+ {
+ $cell = new TableCell('Hello World');
+
+ $html = $cell->getHtml();
+
+ self::assertSame('Hello World', $html);
+ self::assertContains('t_string', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with integer value
+ */
+ public function testGetHtmlIntegerValue()
+ {
+ $cell = new TableCell(123);
+
+ $html = $cell->getHtml();
+
+ self::assertSame('123', $html);
+ self::assertContains('t_int', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with float value
+ */
+ public function testGetHtmlFloatValue()
+ {
+ $cell = new TableCell(45.67);
+
+ $html = $cell->getHtml();
+
+ self::assertSame('45.67', $html);
+ self::assertContains('t_float', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with true value
+ */
+ public function testGetHtmlTrueValue()
+ {
+ $cell = new TableCell(true);
+
+ $html = $cell->getHtml();
+
+ self::assertSame('true', $html);
+ self::assertContains('t_true', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with false value
+ */
+ public function testGetHtmlFalseValue()
+ {
+ $cell = new TableCell(false);
+
+ $html = $cell->getHtml();
+
+ self::assertSame('false', $html);
+ self::assertContains('t_false', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with null value
+ */
+ public function testGetHtmlNullValue()
+ {
+ $cell = new TableCell(null);
+
+ $html = $cell->getHtml();
+
+ self::assertSame('null', $html);
+ self::assertContains('t_null', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with array value
+ */
+ public function testGetHtmlArrayValue()
+ {
+ $cell = new TableCell(['a', 'b', 'c']);
+
+ $html = $cell->getHtml();
+
+ self::assertStringContainsString('Array', $html);
+ self::assertContains('t_array', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with object having __toString
+ */
+ public function testGetHtmlObjectWithToString()
+ {
+ $obj = new \bdk\Test\Table\Fixture\Stringable('String Representation');
+
+ $cell = new TableCell($obj);
+ $html = $cell->getHtml();
+
+ self::assertSame('String Representation', $html);
+ self::assertContains('t_object', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with DateTime object
+ */
+ public function testGetHtmlDateTimeObject()
+ {
+ $date = new DateTime('2025-12-29 10:30:00');
+
+ $cell = new TableCell($date);
+ $html = $cell->getHtml();
+
+ self::assertStringContainsString('2025-12-29', $html);
+ self::assertStringContainsString('10:30:00', $html);
+ self::assertContains('t_object', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with DateTimeImmutable object
+ */
+ /*
+ public function testGetHtmlDateTimeImmutableObject()
+ {
+ $date = new DateTimeImmutable('2025-01-15 14:45:30');
+
+ $cell = new TableCell($date);
+ $html = $cell->getHtml();
+
+ self::assertStringContainsString('2025-01-15', $html);
+ self::assertStringContainsString('14:45:30', $html);
+ self::assertContains('t_object', $cell->getAttribs()['class']);
+ }
+ */
+
+ /**
+ * Test getHtml with object without __toString
+ */
+ public function testGetHtmlObjectWithoutToString()
+ {
+ $obj = new \stdClass();
+
+ $cell = new TableCell($obj);
+ $html = $cell->getHtml();
+
+ self::assertSame('stdClass', $html);
+ self::assertContains('t_object', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with undefined value
+ */
+ public function testGetHtmlUndefinedValue()
+ {
+ $cell = new TableCell(Factory::VAL_UNDEFINED);
+
+ $html = $cell->getHtml();
+
+ self::assertSame('', $html);
+ self::assertContains('t_undefined', $cell->getAttribs()['class']);
+ }
+
+ /**
+ * Test getHtml with special characters
+ */
+ public function testGetHtmlSpecialCharacters()
+ {
+ $cell = new TableCell('');
+
+ $html = $cell->getHtml();
+
+ self::assertStringContainsString('<script>', $html);
+ self::assertStringContainsString('</script>', $html);
+ self::assertStringNotContainsString(' |
|