Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .config/phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
bootstrap="../vendor/autoload.php"
cacheResultFile="../.phpunit.cache/test-results"
cacheResultFile="../build/.phpunit.cache/test-results"
convertDeprecationsToExceptions="true"
failOnRisky="true"
failOnWarning="true"
Expand All @@ -20,7 +20,7 @@
</testsuite>
</testsuites>

<coverage cacheDirectory="../.phpunit.cache/code-coverage" processUncoveredFiles="false">
<coverage cacheDirectory="../build/.phpunit.cache/code-coverage" processUncoveredFiles="false">
<include>
<directory suffix=".php">../src/</directory>
</include>
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/php.yml
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ jobs:
- '8.1' # from 2021-11 to 2023-11 (2025-12)
- '8.2' # from 2022-12 to 2024-12 (2026-12)
- '8.3' # from 2023-11 to 2025-12 (2027-12)
- '8.4' # from 2024-11 to 2026-12 (2028-12)
steps:
- uses: actions/checkout@v4
- uses: shivammathur/setup-php@v2
Expand Down Expand Up @@ -122,6 +123,7 @@ jobs:
- '8.1' # from 2021-11 to 2023-11 (2025-12)
- '8.2' # from 2022-12 to 2024-12 (2026-12)
- '8.3' # from 2023-11 to 2025-12 (2027-12)
- '8.4' # from 2024-11 to 2026-12 (2028-12)
steps:
- uses: actions/checkout@v4
- uses: docker://pipelinecomponents/php-codesniffer
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# Directories to ignore
/build
/vendor

# Files to ignore
Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@
"require": {
"php": "^8.0",
"ext-mbstring": "*",
"laminas/laminas-diactoros": "^2.14",
"laminas/laminas-diactoros": "^3.0",
Comment thread
Potherca marked this conversation as resolved.
Outdated
"league/flysystem": "^1.0",
"mjrider/flysystem-factory": "^0.7",
"pdsinterop/flysystem-rdf": "^0.5",
"pietercolpaert/hardf": "^0.3",
"psr/http-factory": "^1.0",
"psr/http-message": "^1.0",
"psr/http-message": "^1.1 || ^2.0",
"textalk/websocket": "^1.5"
},
"scripts": {
Expand All @@ -39,6 +39,6 @@
},
"type": "library",
"require-dev": {
"phpunit/phpunit": "^9"
"phpunit/phpunit": "^9.0 | ^10.0"
}
}
105 changes: 105 additions & 0 deletions tests/Unit/ExceptionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
<?php

namespace Unit;

use Pdsinterop\Solid\Resources\Exception;
use PHPUnit\Framework\TestCase;
use TypeError;

/**
* @coversDefaultClass \Pdsinterop\Solid\Resources\Exception
* @covers ::create
*/
class ExceptionTest extends TestCase
{
const MOCK_CONTEXT = ['Test'];
const MOCK_MESSAGE = 'Error: %s';

/**
* @testdox Exception should complain when called without a message
*/
public function testCreateWithoutMessage(): void
{
$this->expectException(TypeError::class);
$this->expectExceptionMessageMatches('/Too few arguments .+ 0 passed/');

Exception::create();
}

/**
* @testdox Exception should complain when called without a context
*/
public function testCreateWithoutContext(): void
{
$this->expectException(TypeError::class);
$this->expectExceptionMessageMatches('/Too few arguments .+ 1 passed/');

Exception::create(self::MOCK_MESSAGE);
}

/**
* @testdox Exception should complain when called with invalid message
*/
public function testCreateWithInvalidMessage(): void
{
$this->expectException(TypeError::class);
$this->expectExceptionMessageMatches('/Argument #1 .+ must be of type string/');

Exception::create(null, self::MOCK_CONTEXT);
}

/**
* @testdox Exception should complain when called with invalid context
*/
public function testCreateWithInvalidContext(): void
{
$this->expectException(TypeError::class);
$this->expectExceptionMessageMatches('/Argument #2 .+ must be of type array/');

Exception::create(self::MOCK_MESSAGE, null);
}

/**
* @testdox Exception should complain when given context does not match provided message format
*/
public function testCreateWithIncorrectContext(): void
{
$this->expectException(\ValueError::class);
$this->expectExceptionMessageMatches('/The arguments array must contain 1 items?, 0 given/');

Exception::create(self::MOCK_MESSAGE, []);
}

/**
* @testdox Exception should be created when called with valid message and context
*/
public function testCreateWithMessageAndContext(): void
{
$expected = Exception::class;
$actual = Exception::create(self::MOCK_MESSAGE, self::MOCK_CONTEXT);

$this->assertInstanceOf($expected, $actual);
}

/**
* @testdox Created Exception should have the correct message when called with a message and context
*/
public function testCreateFormatsErrorMessage(): void
{
$expected = 'Error: Test';
$actual = Exception::create(self::MOCK_MESSAGE, self::MOCK_CONTEXT)->getMessage();

$this->assertSame($expected, $actual);
}

/**
* @testdox Exception should be created when called with a message, context and previous exception
*/
public function testCreateSetsPreviousException(): void
{
$expected = new \Exception('Previous exception');
$actual = Exception::create(self::MOCK_MESSAGE, self::MOCK_CONTEXT, $expected)->getPrevious();

$this->assertSame($expected, $actual);
}
}
200 changes: 200 additions & 0 deletions tests/Unit/ServerTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
<?php

namespace Pdsinterop\Solid\Resources;

use League\Flysystem\FilesystemInterface;
use Pdsinterop\Rdf\Flysystem\Plugin\AsMime;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Message\StreamInterface;
use Psr\Http\Message\UriInterface;
use TypeError;

/**
* @coversDefaultClass \Pdsinterop\Solid\Resources\Server
* @covers \Pdsinterop\Solid\Resources\Server
*/
class ServerTest extends TestCase
{
////////////////////////////////// FIXTURES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

const MOCK_HTTP_METHOD = 'MOCK';
const MOCK_PATH = '/mock/path';

public static function setUpBeforeClass(): void
{
$phpUnitVersion = \PHPUnit\Runner\Version::id();

/* PHP 8.4.0 and PHPUnit 9 triggers a Deprecation Warning, which PHPUnit
* promotes to an Exception, which causes tests to fail.This is fixed in
* PHPUnit v10. As a workaround for v9, instead of loading the real
* interface, a fixed interface is loaded on the fly.
*/
if (
version_compare(PHP_VERSION, '8.4.0', '>=')
&& version_compare($phpUnitVersion, '9.0.0', '>=')
&& version_compare($phpUnitVersion, '10.0.0', '<')
) {
$file = __DIR__ . '/../../vendor/league/flysystem/src/FilesystemInterface.php';
$contents = file_get_contents($file);
$contents = str_replace(['<?php','Handler $handler = null'], ['','?Handler $handler = null'], $contents);
eval($contents);
}
}

/////////////////////////////////// TESTS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\

/**
* @testdox Server should complain when instantiated without a filesystem
* @covers ::__construct
*/
public function testServerConstructWithoutFilesystem()
{
$this->expectException(TypeError::class);
$this->expectExceptionMessageMatches('/Too few arguments .+ 0 passed/');

new Server();
}

/**
* @testdox Server should complain when instantiated without a response
* @covers ::__construct
*/
public function testServerConstructWithoutResponse()
{
$this->expectException(TypeError::class);
$this->expectExceptionMessageMatches('/Too few arguments .+ 1 passed/');

$mockFilesystem = $this->createMock(FilesystemInterface::class);

new Server($mockFilesystem);
}

/**
* @testdox Server should be instantiated when given a filesystem and a response
* @covers ::__construct
*/
public function testServerConstructWithFilesystemAndResponse()
{
$mockFilesystem = $this->createMock(FilesystemInterface::class);
$mockResponse = $this->createMock(ResponseInterface::class);

$server = new Server($mockFilesystem, $mockResponse);

$this->assertInstanceOf(Server::class, $server);
}

/**
* @testdox Server should complain when asked to RespondToRequest without a request
* @covers ::respondToRequest
*/
public function testServerRespondToRequestWithoutRequest()
{
$this->expectException(TypeError::class);
$this->expectExceptionMessageMatches('/Too few arguments .+ 0 passed/');

$mockFilesystem = $this->createMock(FilesystemInterface::class);
$mockResponse = $this->createMock(ResponseInterface::class);

$server = new Server($mockFilesystem, $mockResponse);

$server->respondToRequest();
}

/**
* @testdox Server should complain when asked to RespondToRequest with a request with an unknown HTTP method
*
* @covers ::respondToRequest
*
* @uses \Pdsinterop\Solid\Resources\Exception
*/
public function testServerRespondToRequestWithUnknownHttpMethod()
{
// Assert
$this->expectException(Exception::class);
$this->expectExceptionMessage(vsprintf(Server::ERROR_UNKNOWN_HTTP_METHOD, [self::MOCK_HTTP_METHOD]));

// Arrange
$mockRequest = $this->createMockRequest();
$mockResponse = $this->createMock(ResponseInterface::class);
$mockFilesystem = $this->createMockFilesystem();

//Act
$server = new Server($mockFilesystem, $mockResponse);
$server->respondToRequest($mockRequest);
}

/**
* @testdox Server should return provided response when asked to RespondToRequest with va lid request
*
* @covers ::respondToRequest
*/
public function testServerRespondToRequestWithRequest()
{
// Arrange
$mockFilesystem = $this->createMockFilesystem();
$mockRequest = $this->createMockRequest('GET');
$expected = $this->createMockResponse();

// Act
$server = new Server($mockFilesystem, $expected);
$actual = $server->respondToRequest($mockRequest);

// Assert
$this->assertSame($expected, $actual);
}

////////////////////////////// MOCKS AND STUBS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\

public function createMockFilesystem(): FilesystemInterface|MockObject
{
$mockFilesystem = $this->getMockBuilder(FilesystemInterface::class)
->onlyMethods([
'addPlugin', 'copy', 'createDir', 'delete', 'deleteDir', 'get', 'getMetadata', 'getMimetype', 'getSize', 'getTimestamp', 'getVisibility', 'has', 'listContents', 'put', 'putStream', 'read', 'readAndDelete', 'readStream', 'rename', 'setVisibility', 'update', 'updateStream', 'write', 'writeStream'
])
->addMethods(['asMime'])
->getMock();

$mockAsMime = $this->getMockBuilder(AsMime::class)
// ->onlyMethods(['getMimetype', 'getSize', 'getTimestamp'])
->addMethods(['has'])
->disableOriginalConstructor()
->getMock();

$mockFilesystem->method('asMime')->willReturn($mockAsMime);

return $mockFilesystem;
}

public function createMockRequest($httpMethod = self::MOCK_HTTP_METHOD): ServerRequestInterface|MockObject
{
$mockRequest = $this->createMock(ServerRequestInterface::class);

$mockUri = $this->createMock(UriInterface::class);
$mockUri->method('getPath')->willReturn(self::MOCK_PATH);

$mockBody = $this->createMock(StreamInterface::class);

$mockRequest->method('getUri')->willReturn($mockUri);
$mockRequest->method('getQueryParams')->willReturn([]);
$mockRequest->method('getMethod')->willReturn($httpMethod);
$mockRequest->method('getBody')->willReturn($mockBody);
// $mockRequest->method('getMethod')->willReturn('GET');
$mockRequest->method('getHeaderLine')->willReturn('');

return $mockRequest;
}

public function createMockResponse(): ResponseInterface|MockObject
{
$mockResponse = $this->createMock(ResponseInterface::class);
$mockBody = $this->createMock(StreamInterface::class);

$mockResponse->method('getBody')->willReturn($mockBody);
$mockResponse->method('withStatus')->willReturnSelf();

return $mockResponse;
}
}
20 changes: 0 additions & 20 deletions tests/dummyTest.php

This file was deleted.