Skip to content

Commit 2ce4ca9

Browse files
authored
Merge pull request #36 from pdsinterop/fix/resource-extension-simpler
Fix/resource extension simpler
2 parents 5824233 + 68ff557 commit 2ce4ca9

4 files changed

Lines changed: 241 additions & 45 deletions

File tree

composer.json

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,18 @@
2828
"psr/http-factory": "^1.0",
2929
"psr/http-message": "^1.0"
3030
},
31+
"require-dev": {
32+
"ext-xdebug": "*",
33+
"ext-xml": "*",
34+
"phpunit/phpunit": "^9.5"
35+
},
3136
"scripts": {
3237
"dev:example": "php -S localhost:${PORT:-8080} -t ./src/ ./src/example.php",
33-
"tests:unit": "phpunit --configuration `.config/phpunit.xml.dist` ./tests/unit"
38+
"tests:unit": "phpunit --configuration '.config/phpunit.xml.dist' ./tests/unit"
3439
},
3540
"scripts-descriptions": {
3641
"dev:example": "Run internal PHP development server with example code",
3742
"tests:unit": "Run unit-test with PHPUnit"
3843
},
39-
"type": "library",
40-
"require-dev": {
41-
"phpunit/phpunit": "^9"
42-
}
44+
"type": "library"
4345
}

src/Server.php

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class Server
3434
public const ERROR_PUT_NON_EXISTING_RESOURCE = self::ERROR_PATH_DOES_NOT_EXIST . '. Can not "PUT" non-existing resource. Use "POST" instead';
3535
public const ERROR_UNKNOWN_HTTP_METHOD = 'Unknown or unsupported HTTP METHOD "%s"';
3636

37-
private const MIME_TYPE_DIRECTORY = 'directory';
37+
public const MIME_TYPE_DIRECTORY = 'directory';
3838
private const QUERY_PARAM_HTTP_METHOD = 'http-method';
3939

4040
private const NOTIFICATION_TYPE_CREATE = "Create";
@@ -224,6 +224,25 @@ private function handle(string $method, string $path, $contents, $request): Resp
224224
$filename = $slug;
225225
} else {
226226
$filename = $this->guid();
227+
// FIXME: make this list complete for at least the things we'd expect (turtle, n3, jsonld, ntriples, rdf);
228+
switch ($contentType) {
229+
case '':
230+
// FIXME: if no content type was passed, we should reject the request according to the spec;
231+
break;
232+
case "text/plain":
233+
$filename .= ".txt";
234+
break;
235+
case "text/turtle":
236+
$filename .= ".ttl";
237+
break;
238+
case "text/html":
239+
$filename .= ".html";
240+
break;
241+
case "application/json":
242+
case "application/ld+json":
243+
$filename .= ".json";
244+
break;
245+
}
227246
}
228247

229248
$link = $request->getHeaderLine("Link");
@@ -232,25 +251,6 @@ private function handle(string $method, string $path, $contents, $request): Resp
232251
$response = $this->handleCreateDirectoryRequest($response, $path . $filename);
233252
break;
234253
default:
235-
// FIXME: make this list complete for at least the things we'd expect (turtle, n3, jsonld, ntriples, rdf);
236-
switch ($contentType) {
237-
case '':
238-
// FIXME: if no content type was passed, we should reject the request according to the spec;
239-
break;
240-
case "text/plain":
241-
$filename .= ".txt";
242-
break;
243-
case "text/turtle":
244-
$filename .= ".ttl";
245-
break;
246-
case "text/html":
247-
$filename .= ".html";
248-
break;
249-
case "application/json":
250-
case "application/ld+json":
251-
$filename .= ".json";
252-
break;
253-
}
254254
$response = $this->handleCreateRequest($response, $path . $filename, $contents);
255255
break;
256256
}

tests/dummyTest.php

Lines changed: 0 additions & 20 deletions
This file was deleted.

tests/unit/ServerTest.php

Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
<?php
2+
/**
3+
* Unit Test for the Server class
4+
*/
5+
6+
namespace Pdsinterop\Solid\Resources;
7+
8+
use ArgumentCountError;
9+
use EasyRdf\Graph;
10+
use Laminas\Diactoros\Response;
11+
use Laminas\Diactoros\ServerRequest;
12+
use League\Flysystem\FilesystemInterface;
13+
use PHPUnit\Framework\TestCase;
14+
use Psr\Http\Message\ResponseInterface;
15+
use Psr\Http\Message\ServerRequestInterface;
16+
17+
/**
18+
* @covers \Pdsinterop\Solid\Resources\Server
19+
* @coversDefaultClass \Pdsinterop\Solid\Resources\Server
20+
*
21+
* @uses \Laminas\Diactoros\Response
22+
* @uses \Laminas\Diactoros\ServerRequest
23+
* @uses \Pdsinterop\Solid\Resources\Exception
24+
* @uses \Pdsinterop\Solid\Resources\Server
25+
*/
26+
class ServerTest extends TestCase
27+
{
28+
////////////////////////////////// FIXTURES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
29+
30+
const MOCK_BODY = 'php://temp';
31+
const MOCK_PATH = '/path/to/resource/';
32+
const MOCK_SERVER_PARAMS = [];
33+
const MOCK_UPLOADED_FILES = [];
34+
const MOCK_URL = 'https://example.com' . self::MOCK_PATH;
35+
36+
/////////////////////////////////// TESTS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
37+
38+
/** @testdox Server should complain when instantiated without File System */
39+
public function testInstatiationWithoutFileSystem()
40+
{
41+
$this->expectException(ArgumentCountError::class);
42+
$this->expectExceptionMessageMatches('/Too few arguments .+ 0 passed/');
43+
44+
new Server();
45+
}
46+
47+
/** @testdox Server should complain when instantiated without Response */
48+
public function testInstatiationWithoutResponse()
49+
{
50+
$this->expectException(ArgumentCountError::class);
51+
$this->expectExceptionMessageMatches('/Too few arguments .+ 1 passed/');
52+
53+
$mockFileSystem = $this->getMockBuilder(FilesystemInterface::class)->getMock();
54+
55+
new Server($mockFileSystem);
56+
}
57+
58+
/** @testdox Server should be instantiated when constructed without Graph */
59+
public function testInstatiationWithoutGraph()
60+
{
61+
$mockFileSystem = $this->getMockBuilder(FilesystemInterface::class)->getMock();
62+
$mockResponse = $this->getMockBuilder(ResponseInterface::class)->getMock();
63+
64+
$actual = new Server($mockFileSystem, $mockResponse);
65+
$expected = Server::class;
66+
67+
$this->assertInstanceOf($expected, $actual);
68+
}
69+
70+
/** @testdox Server should be instantiated when constructed with Graph */
71+
public function testInstatiationWithGraph()
72+
{
73+
$mockFileSystem = $this->getMockBuilder(FilesystemInterface::class)->getMock();
74+
$mockResponse = $this->getMockBuilder(ResponseInterface::class)->getMock();
75+
$mockGraph = $this->getMockBuilder(Graph::class)->getMock();
76+
77+
$actual = new Server($mockFileSystem, $mockResponse, $mockGraph);
78+
$expected = Server::class;
79+
80+
$this->assertInstanceOf($expected, $actual);
81+
}
82+
83+
/**
84+
* @testdox Server should complain when asked to respond to a request without a Request
85+
*
86+
* @covers ::respondToRequest
87+
*/
88+
public function testRespondToRequestWithoutRequest()
89+
{
90+
// Arrange
91+
$mockFileSystem = $this->getMockBuilder(FilesystemInterface::class)->getMock();
92+
$mockResponse = $this->getMockBuilder(ResponseInterface::class)->getMock();
93+
$mockGraph = $this->getMockBuilder(Graph::class)->getMock();
94+
95+
$server = new Server($mockFileSystem, $mockResponse, $mockGraph);
96+
97+
// Assert
98+
$this->expectException(ArgumentCountError::class);
99+
$this->expectExceptionMessageMatches('/Too few arguments .+ 0 passed/');
100+
101+
// Act
102+
$server->respondToRequest();
103+
}
104+
105+
/**
106+
* @testdox Server should complain when asked to respond to a Request with an unsupported HTTP METHOD
107+
*
108+
* @covers ::respondToRequest
109+
*
110+
* @dataProvider provideUnsupportedHttpMethods
111+
*/
112+
public function testRespondToRequestWithUnsupportedHttpMethod($httpMethod)
113+
{
114+
// Arrange
115+
$mockFileSystem = $this->getMockBuilder(FilesystemInterface::class)->getMock();
116+
$mockGraph = $this->getMockBuilder(Graph::class)->getMock();
117+
$request = $this->createRequest($httpMethod);
118+
119+
$mockResponse = new Response();
120+
121+
$server = new Server($mockFileSystem, $mockResponse, $mockGraph);
122+
123+
// Assert
124+
$this->expectException(Exception::class);
125+
$this->expectExceptionMessage('Unknown or unsupported HTTP METHOD');
126+
127+
// Act
128+
$server->respondToRequest($request);
129+
}
130+
131+
/**
132+
* @testdox Server should create a resource when asked to create a resource with Slug header present
133+
*
134+
* @covers ::respondToRequest
135+
*
136+
* @dataProvider provideSlugs
137+
*/
138+
public function testRespondToPOSTCreateRequest($slug, $mimetype, $expected)
139+
{
140+
// Arrange
141+
$mockFileSystem = $this->getMockBuilder(FilesystemInterface::class)->getMock();
142+
$mockGraph = $this->getMockBuilder(Graph::class)->getMock();
143+
$request = $this->createRequest('POST', [
144+
'Content-Type' => $mimetype,
145+
'Link' => '',
146+
'Slug' => $slug,
147+
]);
148+
149+
$mockFileSystem
150+
->method('has')
151+
->withAnyParameters()
152+
->willReturnMap([
153+
[self::MOCK_PATH, true],
154+
]);
155+
156+
$mockFileSystem
157+
->method('getMimetype')
158+
->with(self::MOCK_PATH)
159+
->willReturn(Server::MIME_TYPE_DIRECTORY);
160+
161+
$mockFileSystem
162+
->method('write')
163+
->withAnyParameters()
164+
->willReturn(true);
165+
166+
// Act
167+
$server = new Server($mockFileSystem, new Response(), $mockGraph);
168+
$response = $server->respondToRequest($request);
169+
170+
// Assert
171+
$actual = $response->getHeaderLine('Location');
172+
173+
$this->assertEquals(self::MOCK_PATH . $expected, $actual);
174+
}
175+
176+
/////////////////////////////// DATAPROVIDERS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
177+
178+
public static function provideSlugs()
179+
{
180+
return [
181+
// '' => [$slug, $mimetype, $expectedFilename],
182+
'Slug with json extension, with ld+json MIME' => ['Mock Slug.json', 'application/ld+json', 'Mock Slug.json'],
183+
'Slug with jsonld extension, with ld+json MIME' => ['Mock Slug.jsonld', 'application/ld+json', 'Mock Slug.jsonld'],
184+
'Slug with PNG extension, with PNG MIME' => ['Mock Slug.png', 'image/png', 'Mock Slug.png'],
185+
'Slug with some other, extension) with Turtle MIME' => ['Mock Slug.other', 'text/turtle', 'Mock Slug.other'],
186+
'Slug with Turtle extension, with other MIME' => ['Mock Slug.ttl', 'some/other', 'Mock Slug.ttl'],
187+
'Slug with Turtle extension, with Turtle MIME' => ['Mock Slug.ttl', 'text/turtle', 'Mock Slug.ttl'],
188+
'Slug without extension, with some other MIME' => ['Mock Slug', 'some/other', 'Mock Slug'],
189+
'Slug without extension, with turtle MIME' => ['Mock Slug', 'text/turtle', 'Mock Slug'],
190+
];
191+
}
192+
193+
public static function provideUnsupportedHttpMethods()
194+
{
195+
return [
196+
'string:CONNECT' => ['CONNECT'],
197+
'string:TRACE' => ['TRACE'],
198+
'string:UNKNOWN' => ['UNKNOWN'],
199+
];
200+
}
201+
202+
////////////////////////////// MOCKS AND STUBS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\
203+
private function createRequest(string $httpMethod, array $headers = []): ServerRequestInterface
204+
{
205+
return new ServerRequest(
206+
self::MOCK_SERVER_PARAMS,
207+
self::MOCK_UPLOADED_FILES,
208+
self::MOCK_URL,
209+
$httpMethod,
210+
self::MOCK_BODY,
211+
$headers
212+
);
213+
}
214+
}

0 commit comments

Comments
 (0)