diff --git a/src/Analyse/Callback/Iterate/ThroughLargeArray.php b/src/Analyse/Callback/Iterate/ThroughLargeArray.php index 3dd0393a..f87078ea 100644 --- a/src/Analyse/Callback/Iterate/ThroughLargeArray.php +++ b/src/Analyse/Callback/Iterate/ThroughLargeArray.php @@ -85,6 +85,7 @@ public function callMe(): string // Meh, the only reason for the recursion marker // in arrays is because of the $GLOBAL array, which // we will only render once. + // @deprecated Will be removed when we drop 8.0 support if ($key === $recursionMarker) { continue; } diff --git a/src/Analyse/Callback/Iterate/ThroughProperties.php b/src/Analyse/Callback/Iterate/ThroughProperties.php index 8898ba52..1acca274 100644 --- a/src/Analyse/Callback/Iterate/ThroughProperties.php +++ b/src/Analyse/Callback/Iterate/ThroughProperties.php @@ -326,6 +326,8 @@ protected function retrieveValueStatus(ReflectionProperty $refProperty, Reflecti // In a rather buggy state. When the property is not readonly, this may // trigger an // "Error : Internal error: Failed to retrieve the reflection object". + // It was later fixed in PHP 8.1.?. + // @deprecated The try catch will be removed. try { if ($refProperty->isReadOnly()) { $additional .= $messages->getHelp('readonly') . ' '; diff --git a/src/Analyse/Routing/Routing.php b/src/Analyse/Routing/Routing.php index a79d9e63..f1d1285c 100644 --- a/src/Analyse/Routing/Routing.php +++ b/src/Analyse/Routing/Routing.php @@ -81,7 +81,6 @@ public function __construct(Pool $pool) $this->processors[ProcessFloat::class] = $pool->createClass(ProcessFloat::class); $this->processors[ProcessNull::class] = $pool->createClass(ProcessNull::class); $this->processors[ProcessResource::class] = $pool->createClass(ProcessResource::class); - $this->processors[ProcessOther::class] = $pool->createClass(ProcessOther::class); $pool->routing = $this; } @@ -111,7 +110,11 @@ public function analysisHub(Model $model): string } } - // The ProcessOther should prevent this. - return ''; + // Looks like we ran out of processors. + /** @var ProcessOther $processOther */ + $processOther = $this->pool->createClass(ProcessOther::class); + $processOther->canHandle($model); + + return $processOther->handle(); } } diff --git a/src/Analyse/Scalar/String/Callback.php b/src/Analyse/Scalar/String/Callback.php index ce327060..c225f555 100644 --- a/src/Analyse/Scalar/String/Callback.php +++ b/src/Analyse/Scalar/String/Callback.php @@ -76,14 +76,9 @@ public static function isActive(): bool */ public function canHandle($string, Model $model): bool { - try { - if (is_callable($string)) { - $this->handledValue = $string; - return true; - } - } catch (Throwable $exception) { - // Do nothing. - // The autoloading just failed. + if (is_callable($string)) { + $this->handledValue = $string; + return true; } return false; diff --git a/src/Analyse/Scalar/String/Json.php b/src/Analyse/Scalar/String/Json.php index f64a5a79..24583304 100644 --- a/src/Analyse/Scalar/String/Json.php +++ b/src/Analyse/Scalar/String/Json.php @@ -93,6 +93,7 @@ public function canHandle($string, Model $model): bool return false; } + // @deprecated Will be removed once we drop 8.3 support. if (function_exists('json_validate') && json_validate($string)) { // Doing it the PHP 8.3 way. $this->model = $model; @@ -122,7 +123,7 @@ protected function handle(): array { if (empty($this->decodedJson)) { // We will not decode it again, if we already have a result. - // The "if" will be removed in PHP 8.3. + // @deprecated The "if" will be removed in PHP 8.3. $this->decodedJson = json_decode($this->handledValue); } diff --git a/tests/Fixtures/DeepGetterFixture.php b/tests/Fixtures/DeepGetterFixture.php index fd0ff4ea..3cffb706 100644 --- a/tests/Fixtures/DeepGetterFixture.php +++ b/tests/Fixtures/DeepGetterFixture.php @@ -154,6 +154,23 @@ class DeepGetterFixture */ protected $false = false; + /** + * This is clearly uppercase. + * + * @var int + */ + protected $Uppercase = 1; + + /** + * Things! + * + * @return int + */ + public function Theuppercase(): int + { + return $this->Uppercase; + } + /** * @return string */ diff --git a/tests/Scripts/Bootstrap.php b/tests/Scripts/Bootstrap.php index 370c87fa..fe3047b0 100644 --- a/tests/Scripts/Bootstrap.php +++ b/tests/Scripts/Bootstrap.php @@ -46,10 +46,12 @@ $callbackScalar = '\\Brainworxx\\Krexx\\Analyse\\Scalar\\String\\'; $caller = '\\Brainworxx\\Krexx\\Analyse\\Caller\\'; $factory = '\\Brainworxx\\Krexx\\Service\\Factory\\'; +$scalaString = '\\Brainworxx\\Krexx\\Analyse\\Scalar\String\\'; AbstractHelper::defineFunctionMock($analyseRoutingProcess, 'class_exists'); AbstractHelper::defineFunctionMock($analyseRoutingProcess, 'is_object'); AbstractHelper::defineFunctionMock($analyseRoutingProcess, 'is_resource'); +AbstractHelper::defineFunctionMock($analyseRoutingProcess, 'debug_backtrace'); AbstractHelper::defineFunctionMock($serviceFlow, 'ini_get'); AbstractHelper::defineFunctionMock($serviceFlow, 'time'); AbstractHelper::defineFunctionMock($serviceFlow, 'memory_get_usage'); @@ -75,6 +77,8 @@ AbstractHelper::defineFunctionMock($view, 'defined'); AbstractHelper::defineFunctionMock($caller, 'time'); AbstractHelper::defineFunctionMock($factory, 'getmypid'); +AbstractHelper::defineFunctionMock($scalaString, 'class_exists'); + // Register a shutdown method to die, so we get no output on the shell. register_shutdown_function(function () { diff --git a/tests/Unit/Analyse/Callback/Iterate/ThroughPropertiesTest.php b/tests/Unit/Analyse/Callback/Iterate/ThroughPropertiesTest.php index c7864b55..5c29a55a 100644 --- a/tests/Unit/Analyse/Callback/Iterate/ThroughPropertiesTest.php +++ b/tests/Unit/Analyse/Callback/Iterate/ThroughPropertiesTest.php @@ -38,6 +38,7 @@ use Brainworxx\Krexx\Analyse\Callback\Iterate\ThroughProperties; use Brainworxx\Krexx\Analyse\Declaration\PropertyDeclaration; use Brainworxx\Krexx\Analyse\Model; +use Brainworxx\Krexx\Service\Flow\Emergency; use Brainworxx\Krexx\Service\Reflection\ReflectionClass; use Brainworxx\Krexx\Service\Reflection\UndeclaredProperty; use Brainworxx\Krexx\Tests\Fixtures\AttributesFixture; @@ -519,6 +520,36 @@ public function testCallMeAttributes() ); } + public function testCallMeEmergency() + { + // Test the events. + // We do not expect a stop event. + $this->mockEventService([$this->startEvent, $this->throughProperties]); + + // Make sure to stop everything in its tracks. + $emergencyHandlerMock = $this->createMock(Emergency::class); + $emergencyHandlerMock->expects($this->once()) + ->method('checkEmergencyBreak') + ->willReturn(true); + Krexx::$pool->emergencyHandler = $emergencyHandlerMock; + + // Create a fixture. + $subject = new AttributesFixture(); + $fixture = [ + $this->throughProperties::PARAM_REF => new ReflectionClass($subject), + $this->throughProperties::PARAM_DATA => [ + new ReflectionProperty(AttributesFixture::class, static::PROPERTY), + ] + ]; + + // Run the test + $this->assertEquals( + '', + $this->throughProperties->setParameters($fixture)->callMe(), + 'We use the normal routing. If there is any HTML in there, the break has failed!' + ); + } + /** * Special tests for PHP 8, actually with some 7.4'er stuff. */ diff --git a/tests/Unit/Analyse/Caller/CallerFinderTest.php b/tests/Unit/Analyse/Caller/CallerFinderTest.php index 32fa3f48..7659b15a 100644 --- a/tests/Unit/Analyse/Caller/CallerFinderTest.php +++ b/tests/Unit/Analyse/Caller/CallerFinderTest.php @@ -35,6 +35,7 @@ namespace Brainworxx\Krexx\Tests\Unit\Analyse\Caller; +use Brainworxx\Krexx\Analyse\Callback\CallbackConstInterface; use Brainworxx\Krexx\Analyse\Caller\AbstractCaller; use Brainworxx\Krexx\Analyse\Caller\BacktraceConstInterface; use Brainworxx\Krexx\Analyse\Caller\CallerFinder; @@ -254,6 +255,64 @@ public function testFindCallerUnreadableSource() $this->assertArrayHasKey(BacktraceConstInterface::TRACE_DATE, $result); } + /** + * Test the finding without a valid url. + */ + public function testFindCallerNoUrl() + { + $this->mockDebugBacktrace() + ->expects($this->once()) + ->willReturn($this->createFixture(75)); + + // We need a different pool mock. + $poolMock = $this->createMock(Pool::class); + $poolMock->expects($this->any()) + ->method('getServer') + ->willReturn([ + 'SERVER_PROTOCOL' => 'abcd/', + 'SERVER_PORT' => 123, + 'SERVER_NAME' => 'localhorst', + 'HTTPS' => 'on' + ]); + $poolMock->fileService = Krexx::$pool->fileService; + $poolMock->encodingService = Krexx::$pool->encodingService; + $poolMock->config = Krexx::$pool->config; + $poolMock->emergencyHandler = Krexx::$pool->emergencyHandler; + $poolMock->messages = Krexx::$pool->messages; + $poolMock->expects($this->any()) + ->method('createClass') + ->willReturnCallback(function ($classname) { + return Krexx::$pool->createClass($classname); + }); + $this->callerFinder = new CallerFinder($poolMock); + + // Run the test + $result = $this->callerFinder->findCaller('', $this->subjectVar); + $this->assertEquals('n/a', $result[BacktraceConstInterface::TRACE_URL]); + } + + /** + * Manipulate the lookup array to prevent finding anything. + */ + public function testFindCallerNoResult() + { + $this->mockDebugBacktrace() + ->expects($this->once()) + ->willReturn($this->createFixture(75)); + $this->setValueByReflection('callPattern', [], $this->callerFinder); + + // Run the test + $result = $this->callerFinder->findCaller('', $this->subjectVar); + $this->assertEquals( + CallbackConstInterface::UNKNOWN_VALUE, + $result[BacktraceConstInterface::TRACE_VARNAME] + ); + $this->assertEquals( + 'Analysis of ' . CallbackConstInterface::UNKNOWN_VALUE . ', string', + $result[BacktraceConstInterface::TRACE_TYPE] + ); + } + /** * Test the caller finder with the forced logger. */ diff --git a/tests/Unit/Analyse/Code/ScopeTest.php b/tests/Unit/Analyse/Code/ScopeTest.php index 90276936..e71d51b9 100644 --- a/tests/Unit/Analyse/Code/ScopeTest.php +++ b/tests/Unit/Analyse/Code/ScopeTest.php @@ -39,6 +39,7 @@ use Brainworxx\Krexx\Analyse\Code\Scope; use Brainworxx\Krexx\Analyse\Model; use Brainworxx\Krexx\Service\Flow\Emergency; +use Brainworxx\Krexx\Tests\Fixtures\PublicFixture; use Brainworxx\Krexx\Tests\Helpers\AbstractHelper; use Brainworxx\Krexx\Krexx; use stdClass; @@ -121,8 +122,9 @@ public function testTestModelForCodegen() $object = new stdClass(); $array = []; $string = 'whatever'; + $objectWithPrivate = new PublicFixture(); - // No genereation for 'some' scope. + // No generation for 'some' scope. $this->setNestingLevel(1); $this->scope->setScope('some'); $model = new Model(Krexx::$pool); @@ -144,6 +146,17 @@ public function testTestModelForCodegen() $model->setData($object); $this->assertTrue($this->scope->testModelForCodegen($model)); + // Code generation with a real class on level 1 + $messages = Krexx::$pool->messages; + $this->setNestingLevel(1); + $model->setData($objectWithPrivate) + ->setType( + $messages->getHelp('private') . ' ' . $messages->getHelp('inherited') + ); + $this->scope->setScope('$this'); + $this->assertFalse($this->scope->testModelForCodegen($model)); + $model->setType(''); + // Code generation for a level 2 array. $this->setNestingLevel(2); $model->setData($array); diff --git a/tests/Unit/Analyse/Getter/ByMethodNameTest.php b/tests/Unit/Analyse/Getter/ByMethodNameTest.php index 04094f56..365a9777 100644 --- a/tests/Unit/Analyse/Getter/ByMethodNameTest.php +++ b/tests/Unit/Analyse/Getter/ByMethodNameTest.php @@ -226,7 +226,14 @@ public function testRetrieveItDeep() 'expectation' => true, 'propertyName' => 'myPropertyOne', 'hasResult' => true - ] + ], + [ + 'reflection' => $classReflection->getMethod('Theuppercase'), + 'prefix' => 'get', + 'expectation' => null, + 'propertyName' => 'Uppercase', + 'hasResult' => false + ], ]; $this->validateResults($fixture, $classReflection); } diff --git a/tests/Unit/Analyse/Routing/Process/ProcessBacktraceTest.php b/tests/Unit/Analyse/Routing/Process/ProcessBacktraceTest.php index be6bce3b..111b3569 100644 --- a/tests/Unit/Analyse/Routing/Process/ProcessBacktraceTest.php +++ b/tests/Unit/Analyse/Routing/Process/ProcessBacktraceTest.php @@ -49,11 +49,11 @@ #[CoversMethod(ProcessBacktrace::class, 'getBacktrace')] class ProcessBacktraceTest extends AbstractHelper { - - protected function setUp(): void + /** + * Mock the debug backtrace, to provide a fixture. + */ + protected function mockDebugBacktrace() { - parent::setUp(); - $data = 'data'; $someFile = 'some file'; $debugBacktrace = $this->getFunctionMock('\\Brainworxx\\Krexx\\Analyse\\Routing\\Process\\', 'debug_backtrace'); @@ -95,6 +95,7 @@ public function testConstruct() public function testProcessNormal() { $this->mockEmergencyHandler(); + $this->mockDebugBacktrace(); // Inject the RenderNothing. $renderNothing = new RenderNothing(Krexx::$pool); @@ -159,6 +160,7 @@ public function testProcessNormal() public function testProcessEmpty() { $this->mockEmergencyHandler(); + $this->mockDebugBacktrace(); // Inject the RenderNothing. $renderNothing = new RenderNothing(Krexx::$pool); @@ -182,7 +184,7 @@ public function testProcessEmpty() // Check the parameters $data = 'data'; - $someFile = $orgPath = 'some file'; + $orgPath = 'some file'; for ($i = 0; $i <= 2; $i++) { /** @var \Brainworxx\Krexx\Analyse\Model $model */ $model = $renderNothing->model['renderExpandableChild'][$i]; @@ -213,4 +215,23 @@ public function testProcessEmpty() ); } } + + /** + * We mock the debug_backtrace, and make it return an empty value to + * simulate a tiny backtrace. + */ + public function testProcessReallyEmpty() + { + $this->mockEmergencyHandler(); + + $backtraceMock = $this->getFunctionMock( + '\\Brainworxx\\Krexx\\Analyse\\Routing\\Process\\', + 'debug_backtrace' + ); + $backtraceMock->expects($this->once()) + ->willReturn([]); + + $processBacktrace = new ProcessBacktrace(Krexx::$pool); + $this->assertEquals('', $processBacktrace->handle()); + } } diff --git a/tests/Unit/Analyse/Routing/Process/ProcessStringTest.php b/tests/Unit/Analyse/Routing/Process/ProcessStringTest.php index 04692c7c..788b4b32 100644 --- a/tests/Unit/Analyse/Routing/Process/ProcessStringTest.php +++ b/tests/Unit/Analyse/Routing/Process/ProcessStringTest.php @@ -42,8 +42,10 @@ use Brainworxx\Krexx\Analyse\Routing\Process\ProcessString; use Brainworxx\Krexx\Krexx; use Brainworxx\Krexx\Service\Config\Config; +use Brainworxx\Krexx\Service\Config\ConfigConstInterface; use Brainworxx\Krexx\Service\Config\Fallback; use Brainworxx\Krexx\Service\Config\From\File; +use Brainworxx\Krexx\Service\Flow\Recursion; use Brainworxx\Krexx\Service\Misc\Encoding; use Brainworxx\Krexx\Service\Misc\FileinfoDummy; use Brainworxx\Krexx\Service\Plugin\PluginConfigInterface; @@ -235,20 +237,10 @@ public function testProcessWithLinebreaks() } /** - * Testing the triggering of the scalar analysis and its recursion handling.r + * Testing the triggering of the scalar analysis and its recursion handling. */ public function testProcessWithScalar() { - // Activate the scalar analysis. - Krexx::$pool->rewrite[File::class] = ConfigSupplier::class; - ConfigSupplier::$overwriteValues[Fallback::SETTING_ANALYSE_SCALAR] = 'true'; - - // To prevent a bad rating, I have to do something with the newly - // instantiated configuration. If I don't, it's considered a bug. - // Hence, I do "something" with it. - $whatever = new Config(\Krexx::$pool); - $whatever->getLogDir(); - $fixture = '{"whatever": "okay"}'; $renderNothing = new RenderNothing(Krexx::$pool); Krexx::$pool->render = $renderNothing; @@ -277,6 +269,38 @@ public function testProcessWithScalar() ); } + public function testProcessWithoutScalar() + { + // Deactivate the scalar analysis. + Krexx::$pool->rewrite[File::class] = ConfigSupplier::class; + ConfigSupplier::$overwriteValues[ConfigConstInterface::SETTING_ANALYSE_SCALAR] = false; + new Config(\Krexx::$pool); + + $fixture = '{"whatever": "okay"}'; + $renderNothing = new RenderNothing(Krexx::$pool); + Krexx::$pool->render = $renderNothing; + + $recursionHandlerMock = $this->createMock(Recursion::class); + $recursionHandlerMock->expects($this->never()) + ->method('isInMetaHive'); + $recursionHandlerMock->expects($this->never()) + ->method('addToMetaHive'); + Krexx::$pool->recursionHandler = $recursionHandlerMock; + + $model = new Model(Krexx::$pool); + $model->setData($fixture); + + $this->processString = new ProcessString(Krexx::$pool); + $this->processString->canHandle($model); + $this->processString->handle(); + + $this->assertCount( + 1, + $renderNothing->model['renderExpandableChild'], + 'The first one should be in the expandable child.' + ); + } + /** * Prepare the mocks and run the test. Nice, huh? * The things you do to prevent a bad rating . . . diff --git a/tests/Unit/Analyse/Routing/RoutingTest.php b/tests/Unit/Analyse/Routing/RoutingTest.php index 5be31ec3..31f91a27 100644 --- a/tests/Unit/Analyse/Routing/RoutingTest.php +++ b/tests/Unit/Analyse/Routing/RoutingTest.php @@ -42,6 +42,7 @@ use Brainworxx\Krexx\Service\Flow\Emergency; use Brainworxx\Krexx\Tests\Helpers\AbstractHelper; use Brainworxx\Krexx\Krexx; +use Brainworxx\Krexx\Tests\Helpers\RenderNothing; use PHPUnit\Framework\Attributes\CoversMethod; #[CoversMethod(Routing::class, '__construct')] @@ -151,4 +152,23 @@ public function testAnalysisHubString() $this->assertEquals(static::ROUTING_MOCK_RETURN_VALUE, $this->mockRouting(ProcessString::class, $model)); } + + /** + * We test the final calling of the ProcessOther after everything else + * has failed. + */ + public function testAnalysisHubOther() + { + $renderNothing = new RenderNothing(Krexx::$pool); + Krexx::$pool->render = $renderNothing; + + // Create the model. + $model = new Model(Krexx::$pool); + $model->setData('some string'); + $routing = new Routing(Krexx::$pool); + $this->setValueByReflection('processors', [], $routing); + $routing->analysisHub($model); + + $this->assertTrue(in_array(Krexx::$pool->messages->getHelp('unhandedOtherHelp'), $model->getJson())); + } } diff --git a/tests/Unit/Analyse/Scalar/String/ClassNameTest.php b/tests/Unit/Analyse/Scalar/String/ClassNameTest.php index cc8657d8..23065ba0 100644 --- a/tests/Unit/Analyse/Scalar/String/ClassNameTest.php +++ b/tests/Unit/Analyse/Scalar/String/ClassNameTest.php @@ -76,6 +76,27 @@ public function testCanHandle() ); } + /** + * Testing the failure of the autoloading. + */ + public function testCanHandleError() + { + $className = new ClassName(Krexx::$pool); + $model = new Model(Krexx::$pool); + + $classExistsMock = $this->getFunctionMock( + '\\Brainworxx\\Krexx\\Analyse\\Scalar\String\\', + 'class_exists' + ); + $classExistsMock->expects($this->once()) + ->willThrowException(new \Exception()); + + $this->assertFalse( + $className->canHandle(static::class, $model), + 'Throwing an error must always result in false.' + ); + } + /** * Test the handling of the json. */ diff --git a/tests/Unit/Analyse/Scalar/String/XmlTest.php b/tests/Unit/Analyse/Scalar/String/XmlTest.php index 1b890a2b..71d4237e 100644 --- a/tests/Unit/Analyse/Scalar/String/XmlTest.php +++ b/tests/Unit/Analyse/Scalar/String/XmlTest.php @@ -43,6 +43,7 @@ use Krexx; use PHPUnit\Framework\Attributes\CoversMethod; +#[CoversMethod(Xml::class, '__construct')] #[CoversMethod(Xml::class, 'handle')] #[CoversMethod(Xml::class, 'canHandle')] #[CoversMethod(Xml::class, 'errorCallback')] diff --git a/tests/Unit/Declaration/MethodDeclarationTest.php b/tests/Unit/Declaration/MethodDeclarationTest.php index a3982197..bd405e54 100644 --- a/tests/Unit/Declaration/MethodDeclarationTest.php +++ b/tests/Unit/Declaration/MethodDeclarationTest.php @@ -37,6 +37,7 @@ use Brainworxx\Krexx\Analyse\Declaration\AbstractDeclaration; use Brainworxx\Krexx\Analyse\Declaration\MethodDeclaration; +use Brainworxx\Krexx\Krexx; use Brainworxx\Krexx\Tests\Fixtures\ComplexMethodFixture; use Brainworxx\Krexx\Tests\Fixtures\LoggerCallerFixture; use Brainworxx\Krexx\Tests\Fixtures\MethodParameterFixture; @@ -82,6 +83,30 @@ public function testRetrieveDeclaration() DIRECTORY_SEPARATOR . 'Fixtures' . DIRECTORY_SEPARATOR . 'TraitFixture.php', $result); } + /** + * Test the retrieval of an unknown declaration. + */ + public function testRetrieveDeclarationUnknown() + { + $reflectionMethodMock = $this->createMock(\ReflectionMethod::class); + $reflectionClassMock = $this->createMock(\ReflectionClass::class); + $reflectionMethodMock->expects($this->once()) + ->method('getDeclaringClass') + ->willReturn($reflectionClassMock); + $reflectionMethodMock->expects($this->once()) + ->method('getFileName') + ->willReturn(''); + $reflectionClassMock->expects($this->once()) + ->method('isInternal') + ->willReturn(false); + $reflectionClassMock->expects($this->never()) + ->method('getFileName'); + + $methodDeclaration = new MethodDeclaration(\Krexx::$pool); + $result = $methodDeclaration->retrieveDeclaration($reflectionMethodMock); + $this->assertEquals(Krexx::$pool->messages->getHelp('unknownDeclaration'), $result); + } + /** * Testing the retrieval of the return type by reflections. */ @@ -156,4 +181,4 @@ public function testRetrieveParameterType() ); } } -} \ No newline at end of file +}