engine = self::$container->get(\Twig\Environment::class); } private function buildController(): WebdavController { $storedObjectManager = new MockedStoredObjectManager(); return new WebdavController($this->engine, $storedObjectManager); } private function buildDocument(): StoredObject { $object = (new StoredObject()) ->setType('application/vnd.oasis.opendocument.text'); $reflectionObject = new \ReflectionClass($object); $reflectionObjectUuid = $reflectionObject->getProperty('uuid'); $reflectionObjectUuid->setValue($object, Uuid::fromString('716e6688-4579-4938-acf3-c4ab5856803b')); return $object; } public function testGet(): void { $controller = $this->buildController(); $response = $controller->getDocument($this->buildDocument()); self::assertEquals(200, $response->getStatusCode()); self::assertEquals('abcde', $response->getContent()); self::assertContains('etag', $response->headers->keys()); self::assertStringContainsString('ab56b4', $response->headers->get('etag')); } public function testOptionsOnDocument(): void { $controller = $this->buildController(); $response = $controller->optionsDocument($this->buildDocument()); self::assertEquals(200, $response->getStatusCode()); self::assertContains('allow', $response->headers->keys()); foreach (explode(',', 'OPTIONS,GET,HEAD,POST,DELETE,TRACE,PROPFIND,PROPPATCH,COPY,MOVE,PUT') as $method) { self::assertStringContainsString($method, $response->headers->get('allow')); } self::assertContains('dav', $response->headers->keys()); self::assertStringContainsString('1', $response->headers->get('dav')); } public function testOptionsOnDirectory(): void { $controller = $this->buildController(); $response = $controller->optionsDirectory($this->buildDocument()); self::assertEquals(200, $response->getStatusCode()); self::assertContains('allow', $response->headers->keys()); foreach (explode(',', 'OPTIONS,GET,HEAD,POST,DELETE,TRACE,PROPFIND,PROPPATCH,COPY,MOVE,PUT') as $method) { self::assertStringContainsString($method, $response->headers->get('allow')); } self::assertContains('dav', $response->headers->keys()); self::assertStringContainsString('1', $response->headers->get('dav')); } /** * @dataProvider generateDataPropfindDocument */ public function testPropfindDocument(string $requestContent, int $expectedStatusCode, string $expectedXmlResponse, string $message): void { $controller = $this->buildController(); $request = new Request([], [], [], [], [], [], $requestContent); $request->setMethod('PROPFIND'); $response = $controller->propfindDocument($this->buildDocument(), $request); self::assertEquals($expectedStatusCode, $response->getStatusCode()); self::assertContains('content-type', $response->headers->keys()); self::assertStringContainsString('text/xml', $response->headers->get('content-type')); self::assertTrue((new \DOMDocument())->loadXML($response->getContent()), $message . " test that the xml response is a valid xml"); self::assertXmlStringEqualsXmlString($expectedXmlResponse, $response->getContent(), $message); } /** * @dataProvider generateDataPropfindDirectory */ public function testPropfindDirectory(string $requestContent, int $expectedStatusCode, string $expectedXmlResponse, string $message): void { $controller = $this->buildController(); $request = new Request([], [], [], [], [], [], $requestContent); $request->setMethod('PROPFIND'); $request->headers->add(["Depth" => "0"]); $response = $controller->propfindDirectory($this->buildDocument(), $request); self::assertEquals($expectedStatusCode, $response->getStatusCode()); self::assertContains('content-type', $response->headers->keys()); self::assertStringContainsString('text/xml', $response->headers->get('content-type')); self::assertTrue((new \DOMDocument())->loadXML($response->getContent()), $message . " test that the xml response is a valid xml"); self::assertXmlStringEqualsXmlString($expectedXmlResponse, $response->getContent(), $message); } public function testHeadDocument(): void { $controller = $this->buildController(); $response = $controller->headDocument($this->buildDocument()); self::assertEquals(200, $response->getStatusCode()); self::assertContains('content-length', $response->headers->keys()); self::assertContains('content-type', $response->headers->keys()); self::assertContains('etag', $response->headers->keys()); self::assertEquals('ab56b4d92b40713acc5af89985d4b786', $response->headers->get('etag')); self::assertEquals('application/vnd.oasis.opendocument.text', $response->headers->get('content-type')); self::assertEquals(5, $response->headers->get('content-length')); } public static function generateDataPropfindDocument(): iterable { $content = <<<'XML' XML; $response = <<<'XML' /dav/get/716e6688-4579-4938-acf3-c4ab5856803b/d application/vnd.oasis.opendocument.text HTTP/1.1 200 OK HTTP/1.1 404 Not Found XML; yield [$content, 207, $response, "get IsReadOnly and contenttype from server"]; $content = <<<'XML' XML; $response = <<<'XML' /dav/get/716e6688-4579-4938-acf3-c4ab5856803b/d HTTP/1.1 404 Not Found XML; yield [$content, 207, $response, "get property IsReadOnly"]; yield [ <<<'XML' XML, 207, <<<'XML' /dav/get/716e6688-4579-4938-acf3-c4ab5856803b/d HTTP/1.1 404 Not Found XML, "Test requesting an unknow property" ]; yield [ <<<'XML' XML, 207, <<<'XML' /dav/get/716e6688-4579-4938-acf3-c4ab5856803b/d Wed, 13 Sep 2023 14:15:00 +0200 HTTP/1.1 200 OK XML, "test getting the last modified date" ]; yield [ <<<'XML' XML, 207, <<<'XML' /dav/get/716e6688-4579-4938-acf3-c4ab5856803b/d Wed, 13 Sep 2023 14:15:00 +0200 5 "ab56b4d92b40713acc5af89985d4b786" application/vnd.oasis.opendocument.text HTTP/1.1 200 OK XML, "test finding all properties" ]; } public static function generateDataPropfindDirectory(): iterable { yield [ <<<'XML' XML, 207, <<<'XML' /dav/get/716e6688-4579-4938-acf3-c4ab5856803b/ httpd/unix-directory HTTP/1.1 200 OK HTTP/1.1 404 Not Found XML, "test resourceType and IsReadOnly " ]; yield [ <<<'XML' XML, 207, <<<'XML' /dav/get/716e6688-4579-4938-acf3-c4ab5856803b/ HTTP/1.1 404 Not Found XML, "test creatableContentsInfo" ]; } } class MockedStoredObjectManager implements StoredObjectManagerInterface { public function getLastModified(StoredObject $document): DateTimeInterface { return new \DateTimeImmutable('2023-09-13T14:15'); } public function getContentLength(StoredObject $document): int { return 5; } public function read(StoredObject $document): string { return 'abcde'; } public function write(StoredObject $document, string $clearContent): void {} public function etag(StoredObject $document): string { return 'ab56b4d92b40713acc5af89985d4b786'; } }