aboutsummaryrefslogtreecommitdiffstats
path: root/tests/lib/AppFramework/Utility
diff options
context:
space:
mode:
Diffstat (limited to 'tests/lib/AppFramework/Utility')
-rw-r--r--tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php253
-rw-r--r--tests/lib/AppFramework/Utility/SimpleContainerTest.php260
-rw-r--r--tests/lib/AppFramework/Utility/TimeFactoryTest.php50
3 files changed, 563 insertions, 0 deletions
diff --git a/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php b/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php
new file mode 100644
index 00000000000..00ae4792824
--- /dev/null
+++ b/tests/lib/AppFramework/Utility/ControllerMethodReflectorTest.php
@@ -0,0 +1,253 @@
+<?php
+
+/**
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\AppFramework\Utility;
+
+use OC\AppFramework\Utility\ControllerMethodReflector;
+
+class BaseController {
+ /**
+ * @Annotation
+ */
+ public function test() {
+ }
+
+ /**
+ * @Annotation
+ */
+ public function test2() {
+ }
+
+ /**
+ * @Annotation
+ */
+ public function test3() {
+ }
+}
+
+class MiddleController extends BaseController {
+ /**
+ * @NoAnnotation
+ */
+ public function test2() {
+ }
+
+ public function test3() {
+ }
+
+ /**
+ * @psalm-param int<-4, 42> $rangedOne
+ * @psalm-param int<min, max> $rangedTwo
+ * @psalm-param int<1, 6>|null $rangedThree
+ * @psalm-param ?int<-70, -30> $rangedFour
+ * @return void
+ */
+ public function test4(int $rangedOne, int $rangedTwo, ?int $rangedThree, ?int $rangedFour) {
+ }
+}
+
+class EndController extends MiddleController {
+}
+
+class ControllerMethodReflectorTest extends \Test\TestCase {
+ /**
+ * @Annotation
+ */
+ public function testReadAnnotation(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ '\Test\AppFramework\Utility\ControllerMethodReflectorTest',
+ 'testReadAnnotation'
+ );
+
+ $this->assertTrue($reader->hasAnnotation('Annotation'));
+ }
+
+ /**
+ * @Annotation(parameter=value)
+ */
+ public function testGetAnnotationParameterSingle(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ self::class,
+ __FUNCTION__
+ );
+
+ $this->assertSame('value', $reader->getAnnotationParameter('Annotation', 'parameter'));
+ }
+
+ /**
+ * @Annotation(parameter1=value1, parameter2=value2,parameter3=value3)
+ */
+ public function testGetAnnotationParameterMultiple(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ self::class,
+ __FUNCTION__
+ );
+
+ $this->assertSame('value1', $reader->getAnnotationParameter('Annotation', 'parameter1'));
+ $this->assertSame('value2', $reader->getAnnotationParameter('Annotation', 'parameter2'));
+ $this->assertSame('value3', $reader->getAnnotationParameter('Annotation', 'parameter3'));
+ }
+
+ /**
+ * @Annotation
+ * @param test
+ */
+ public function testReadAnnotationNoLowercase(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ '\Test\AppFramework\Utility\ControllerMethodReflectorTest',
+ 'testReadAnnotationNoLowercase'
+ );
+
+ $this->assertTrue($reader->hasAnnotation('Annotation'));
+ $this->assertFalse($reader->hasAnnotation('param'));
+ }
+
+
+ /**
+ * @Annotation
+ * @param int $test
+ */
+ public function testReadTypeIntAnnotations(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ '\Test\AppFramework\Utility\ControllerMethodReflectorTest',
+ 'testReadTypeIntAnnotations'
+ );
+
+ $this->assertEquals('int', $reader->getType('test'));
+ }
+
+ /**
+ * @Annotation
+ * @param int $a
+ * @param int $b
+ */
+ public function arguments3($a, float $b, int $c, $d) {
+ }
+
+ /**
+ * @requires PHP 7
+ */
+ public function testReadTypeIntAnnotationsScalarTypes(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ '\Test\AppFramework\Utility\ControllerMethodReflectorTest',
+ 'arguments3'
+ );
+
+ $this->assertEquals('int', $reader->getType('a'));
+ $this->assertEquals('float', $reader->getType('b'));
+ $this->assertEquals('int', $reader->getType('c'));
+ $this->assertNull($reader->getType('d'));
+ }
+
+
+ /**
+ * @Annotation
+ * @param double $test something special
+ */
+ public function testReadTypeDoubleAnnotations(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ '\Test\AppFramework\Utility\ControllerMethodReflectorTest',
+ 'testReadTypeDoubleAnnotations'
+ );
+
+ $this->assertEquals('double', $reader->getType('test'));
+ }
+
+ /**
+ * @Annotation
+ * @param string $foo
+ */
+ public function testReadTypeWhitespaceAnnotations(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ '\Test\AppFramework\Utility\ControllerMethodReflectorTest',
+ 'testReadTypeWhitespaceAnnotations'
+ );
+
+ $this->assertEquals('string', $reader->getType('foo'));
+ }
+
+
+ public function arguments($arg, $arg2 = 'hi') {
+ }
+ public function testReflectParameters(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ '\Test\AppFramework\Utility\ControllerMethodReflectorTest',
+ 'arguments'
+ );
+
+ $this->assertEquals(['arg' => null, 'arg2' => 'hi'], $reader->getParameters());
+ }
+
+
+ public function arguments2($arg) {
+ }
+ public function testReflectParameters2(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect(
+ '\Test\AppFramework\Utility\ControllerMethodReflectorTest',
+ 'arguments2'
+ );
+
+ $this->assertEquals(['arg' => null], $reader->getParameters());
+ }
+
+
+ public function testInheritance(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect('Test\AppFramework\Utility\EndController', 'test');
+
+ $this->assertTrue($reader->hasAnnotation('Annotation'));
+ }
+
+
+ public function testInheritanceOverride(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect('Test\AppFramework\Utility\EndController', 'test2');
+
+ $this->assertTrue($reader->hasAnnotation('NoAnnotation'));
+ $this->assertFalse($reader->hasAnnotation('Annotation'));
+ }
+
+
+ public function testInheritanceOverrideNoDocblock(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect('Test\AppFramework\Utility\EndController', 'test3');
+
+ $this->assertFalse($reader->hasAnnotation('Annotation'));
+ }
+
+ public function testRangeDetection(): void {
+ $reader = new ControllerMethodReflector();
+ $reader->reflect('Test\AppFramework\Utility\EndController', 'test4');
+
+ $rangeInfo1 = $reader->getRange('rangedOne');
+ $this->assertSame(-4, $rangeInfo1['min']);
+ $this->assertSame(42, $rangeInfo1['max']);
+
+ $rangeInfo2 = $reader->getRange('rangedTwo');
+ $this->assertSame(PHP_INT_MIN, $rangeInfo2['min']);
+ $this->assertSame(PHP_INT_MAX, $rangeInfo2['max']);
+
+ $rangeInfo3 = $reader->getRange('rangedThree');
+ $this->assertSame(1, $rangeInfo3['min']);
+ $this->assertSame(6, $rangeInfo3['max']);
+
+ $rangeInfo3 = $reader->getRange('rangedFour');
+ $this->assertSame(-70, $rangeInfo3['min']);
+ $this->assertSame(-30, $rangeInfo3['max']);
+ }
+}
diff --git a/tests/lib/AppFramework/Utility/SimpleContainerTest.php b/tests/lib/AppFramework/Utility/SimpleContainerTest.php
new file mode 100644
index 00000000000..33800c7376f
--- /dev/null
+++ b/tests/lib/AppFramework/Utility/SimpleContainerTest.php
@@ -0,0 +1,260 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+namespace Test\AppFramework\Utility;
+
+use OC\AppFramework\Utility\SimpleContainer;
+use OCP\AppFramework\QueryException;
+use Psr\Container\NotFoundExceptionInterface;
+
+interface TestInterface {
+}
+
+class ClassEmptyConstructor implements IInterfaceConstructor {
+}
+
+class ClassSimpleConstructor implements IInterfaceConstructor {
+ public function __construct(
+ public $test,
+ ) {
+ }
+}
+
+class ClassComplexConstructor {
+ public function __construct(
+ public ClassSimpleConstructor $class,
+ public $test,
+ ) {
+ }
+}
+
+class ClassNullableUntypedConstructorArg {
+ public function __construct(
+ public $class,
+ ) {
+ }
+}
+class ClassNullableTypedConstructorArg {
+ public function __construct(
+ public ?\Some\Class $class,
+ ) {
+ }
+}
+
+interface IInterfaceConstructor {
+}
+class ClassInterfaceConstructor {
+ public function __construct(
+ public IInterfaceConstructor $class,
+ public $test,
+ ) {
+ }
+}
+
+
+class SimpleContainerTest extends \Test\TestCase {
+ private $container;
+
+ protected function setUp(): void {
+ $this->container = new SimpleContainer();
+ }
+
+
+
+ public function testRegister(): void {
+ $this->container->registerParameter('test', 'abc');
+ $this->assertEquals('abc', $this->container->query('test'));
+ }
+
+
+ /**
+ * Test querying a class that is not registered without autoload enabled
+ */
+ public function testNothingRegistered(): void {
+ try {
+ $this->container->query('something really hard', false);
+ $this->fail('Expected `QueryException` exception was not thrown');
+ } catch (\Throwable $exception) {
+ $this->assertInstanceOf(QueryException::class, $exception);
+ $this->assertInstanceOf(NotFoundExceptionInterface::class, $exception);
+ }
+ }
+
+
+ /**
+ * Test querying a class that is not registered with autoload enabled
+ */
+ public function testNothingRegistered_autoload(): void {
+ try {
+ $this->container->query('something really hard');
+ $this->fail('Expected `QueryException` exception was not thrown');
+ } catch (\Throwable $exception) {
+ $this->assertInstanceOf(QueryException::class, $exception);
+ $this->assertInstanceOf(NotFoundExceptionInterface::class, $exception);
+ }
+ }
+
+
+
+ public function testNotAClass(): void {
+ $this->expectException(QueryException::class);
+
+ $this->container->query('Test\AppFramework\Utility\TestInterface');
+ }
+
+
+ public function testNoConstructorClass(): void {
+ $object = $this->container->query('Test\AppFramework\Utility\ClassEmptyConstructor');
+ $this->assertTrue($object instanceof ClassEmptyConstructor);
+ }
+
+
+ public function testInstancesOnlyOnce(): void {
+ $object = $this->container->query('Test\AppFramework\Utility\ClassEmptyConstructor');
+ $object2 = $this->container->query('Test\AppFramework\Utility\ClassEmptyConstructor');
+ $this->assertSame($object, $object2);
+ }
+
+ public function testConstructorSimple(): void {
+ $this->container->registerParameter('test', 'abc');
+ $object = $this->container->query(
+ 'Test\AppFramework\Utility\ClassSimpleConstructor'
+ );
+ $this->assertTrue($object instanceof ClassSimpleConstructor);
+ $this->assertEquals('abc', $object->test);
+ }
+
+
+ public function testConstructorComplex(): void {
+ $this->container->registerParameter('test', 'abc');
+ $object = $this->container->query(
+ 'Test\AppFramework\Utility\ClassComplexConstructor'
+ );
+ $this->assertTrue($object instanceof ClassComplexConstructor);
+ $this->assertEquals('abc', $object->class->test);
+ $this->assertEquals('abc', $object->test);
+ }
+
+
+ public function testConstructorComplexInterface(): void {
+ $this->container->registerParameter('test', 'abc');
+ $this->container->registerService(
+ 'Test\AppFramework\Utility\IInterfaceConstructor', function ($c) {
+ return $c->query('Test\AppFramework\Utility\ClassSimpleConstructor');
+ });
+ $object = $this->container->query(
+ 'Test\AppFramework\Utility\ClassInterfaceConstructor'
+ );
+ $this->assertTrue($object instanceof ClassInterfaceConstructor);
+ $this->assertEquals('abc', $object->class->test);
+ $this->assertEquals('abc', $object->test);
+ }
+
+
+ public function testOverrideService(): void {
+ $this->container->registerService(
+ 'Test\AppFramework\Utility\IInterfaceConstructor', function ($c) {
+ return $c->query('Test\AppFramework\Utility\ClassSimpleConstructor');
+ });
+ $this->container->registerService(
+ 'Test\AppFramework\Utility\IInterfaceConstructor', function ($c) {
+ return $c->query('Test\AppFramework\Utility\ClassEmptyConstructor');
+ });
+ $object = $this->container->query(
+ 'Test\AppFramework\Utility\IInterfaceConstructor'
+ );
+ $this->assertTrue($object instanceof ClassEmptyConstructor);
+ }
+
+ public function testRegisterAliasParamter(): void {
+ $this->container->registerParameter('test', 'abc');
+ $this->container->registerAlias('test1', 'test');
+ $this->assertEquals('abc', $this->container->query('test1'));
+ }
+
+ public function testRegisterAliasService(): void {
+ $this->container->registerService('test', function () {
+ return new \StdClass;
+ }, true);
+ $this->container->registerAlias('test1', 'test');
+ $this->assertSame(
+ $this->container->query('test'), $this->container->query('test'));
+ $this->assertSame(
+ $this->container->query('test1'), $this->container->query('test1'));
+ $this->assertSame(
+ $this->container->query('test'), $this->container->query('test1'));
+ }
+
+ public static function sanitizeNameProvider(): array {
+ return [
+ ['ABC\\Foo', 'ABC\\Foo'],
+ ['\\ABC\\Foo', '\\ABC\\Foo'],
+ ['\\ABC\\Foo', 'ABC\\Foo'],
+ ['ABC\\Foo', '\\ABC\\Foo'],
+ ];
+ }
+
+ #[\PHPUnit\Framework\Attributes\DataProvider('sanitizeNameProvider')]
+ public function testSanitizeName($register, $query): void {
+ $this->container->registerService($register, function () {
+ return 'abc';
+ });
+ $this->assertEquals('abc', $this->container->query($query));
+ }
+
+
+ public function testConstructorComplexNoTestParameterFound(): void {
+ $this->expectException(QueryException::class);
+
+ $object = $this->container->query(
+ 'Test\AppFramework\Utility\ClassComplexConstructor'
+ );
+ /* Use the object to trigger DI on PHP >= 8.4 */
+ get_object_vars($object);
+ }
+
+ public function testRegisterFactory(): void {
+ $this->container->registerService('test', function () {
+ return new \StdClass();
+ }, false);
+ $this->assertNotSame(
+ $this->container->query('test'), $this->container->query('test'));
+ }
+
+ public function testRegisterAliasFactory(): void {
+ $this->container->registerService('test', function () {
+ return new \StdClass();
+ }, false);
+ $this->container->registerAlias('test1', 'test');
+ $this->assertNotSame(
+ $this->container->query('test'), $this->container->query('test'));
+ $this->assertNotSame(
+ $this->container->query('test1'), $this->container->query('test1'));
+ $this->assertNotSame(
+ $this->container->query('test'), $this->container->query('test1'));
+ }
+
+ public function testQueryUntypedNullable(): void {
+ $this->expectException(QueryException::class);
+
+ $object = $this->container->query(
+ ClassNullableUntypedConstructorArg::class
+ );
+ /* Use the object to trigger DI on PHP >= 8.4 */
+ get_object_vars($object);
+ }
+
+ public function testQueryTypedNullable(): void {
+ /** @var ClassNullableTypedConstructorArg $service */
+ $service = $this->container->query(ClassNullableTypedConstructorArg::class);
+
+ self::assertNull($service->class);
+ }
+}
diff --git a/tests/lib/AppFramework/Utility/TimeFactoryTest.php b/tests/lib/AppFramework/Utility/TimeFactoryTest.php
new file mode 100644
index 00000000000..276b2d6da4f
--- /dev/null
+++ b/tests/lib/AppFramework/Utility/TimeFactoryTest.php
@@ -0,0 +1,50 @@
+<?php
+
+declare(strict_types=1);
+
+/**
+ * SPDX-FileCopyrightText: 2022 Nextcloud GmbH and Nextcloud contributors
+ * SPDX-License-Identifier: AGPL-3.0-only
+ */
+
+namespace Test\AppFramework\Utility;
+
+use OC\AppFramework\Utility\TimeFactory;
+
+class TimeFactoryTest extends \Test\TestCase {
+ protected TimeFactory $timeFactory;
+
+ protected function setUp(): void {
+ $this->timeFactory = new TimeFactory();
+ }
+
+ public function testNow(): void {
+ $now = $this->timeFactory->now();
+ self::assertSame('UTC', $now->getTimezone()->getName());
+ }
+
+ public function testNowWithTimeZone(): void {
+ $timezone = new \DateTimeZone('Europe/Berlin');
+ $withTimeZone = $this->timeFactory->withTimeZone($timezone);
+
+ $now = $withTimeZone->now();
+ self::assertSame('Europe/Berlin', $now->getTimezone()->getName());
+ }
+
+ public function testGetTimeZone(): void {
+ $expected = new \DateTimeZone('Europe/Berlin');
+ $actual = $this->timeFactory->getTimeZone('Europe/Berlin');
+ self::assertEquals($expected, $actual);
+ }
+
+ public function testGetTimeZoneUTC(): void {
+ $expected = new \DateTimeZone('UTC');
+ $actual = $this->timeFactory->getTimeZone();
+ self::assertEquals($expected, $actual);
+ }
+
+ public function testGetTimeZoneInvalid(): void {
+ $this->expectException(\Exception::class);
+ $this->timeFactory->getTimeZone('blubblub');
+ }
+}