Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
31 changes: 7 additions & 24 deletions .github/workflows/tests.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,36 +14,19 @@ jobs:
max-parallel: 4
matrix:
operatingSystem: [ubuntu-latest]
phpVersion: ['8.1', '8.2', '8.3']
phpVersion: ['8.2', '8.3', '8.4']
fail-fast: false
env:
extensions: curl, fileinfo, gd, mbstring, openssl, pdo, pdo_sqlite, sqlite3, xml, zip
concurrency:
group: ${{ github.ref }}-${{ github.workflow }}-${{ matrix.operatingSystem }}-${{ matrix.phpVersion }}
group: tests-${{ github.ref }}-${{ github.workflow }}-${{ matrix.operatingSystem }}-${{ matrix.phpVersion }}
cancel-in-progress: true
steps:
- name: Checkout Winter CMS
uses: actions/checkout@v4
with:
repository: wintercms/winter
ref: develop

- name: Checkout Winter Docs plugin
uses: actions/checkout@v4
with:
path: plugins/winter/docs

- name: Install PHP
uses: shivammathur/setup-php@v2
- name: Setup Winter CMS
uses: wintercms/setup-winter-action@v1
with:
php-version: ${{ matrix.phpVersion }}
tools: composer:v2
extensions: ${{ env.extensions }}

- name: Install Composer dependencies
run: |
sed -i 's|plugins/myauthor/\*/composer.json|plugins/*/*/composer.json|g' composer.json
composer install --no-interaction --no-progress --no-scripts
winter-ref: wip/1.3
plugin-author: winter
plugin-name: docs

- name: Run tests
run: php artisan winter:test -p Winter.Docs
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
composer.lock
vendor
vendor/
.phpunit.result.cache
.phpunit.cache/
coverage.xml
.DS_Store
11 changes: 10 additions & 1 deletion classes/BaseDocumentation.php
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,16 @@ public function extract(): void
}
}

$zip->extractTo($this->getDownloadPath('extracted'), $toExtract);
if (!$zip->extractTo($this->getDownloadPath('extracted'), $toExtract)) {
throw new ApplicationException(
sprintf(
'Could not extract the documentation for "%s" from the remote source "%s" - %s',
$this->identifier,
$this->source,
$zip->getStatusString()
)
);
}

// Move remaining files into location
$extractPath = $this->getDownloadPath('extracted/' . $this->zipFolder);
Expand Down
25 changes: 21 additions & 4 deletions classes/PHPApiDocumentation.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

namespace Winter\Docs\Classes;

use File;
use Illuminate\Support\Facades\App;
use Twig\TemplateWrapper;
use Winter\Storm\Exception\ApplicationException;
use Winter\Storm\Support\Facades\File;

/**
* PHP API Documentation instance.
Expand All @@ -32,6 +32,11 @@ class PHPApiDocumentation extends BaseDocumentation
*/
protected string $template;

/**
* Path to the Twig template for rendering event API docs.
*/
protected string $eventTemplate;

/**
* Prepared template for rendering API docs.
*/
Expand Down Expand Up @@ -167,12 +172,24 @@ protected function processClassLevel(PHPApiParser $parser, array $classMap, arra
'title' => $key,
];

try {
$rendered = $this->preparedTemplate->render([
'class' => $class,
]);
} catch (\Throwable $e) {
throw new ApplicationException(
sprintf(
'An error occurred while rendering the API documentation for class "%s": %s',
$class['name'],
$e->getMessage()
)
);
}

// Create docs
$this->getStorageDisk()->put(
$this->getProcessedPath(ltrim($baseNamespace . '/' . $key . '.htm')),
$this->prependFrontMatter($class, $this->preparedTemplate->render([
'class' => $class,
]))
$this->prependFrontMatter($class, $rendered)
);

$nav[] = $navItem;
Expand Down
2 changes: 1 addition & 1 deletion classes/PHPApiParser.php
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ public function __construct(string $basePath, array|string $sourcePaths = [], ar
public function parse(): void
{
// Create parser and node finder
$parser = (new ParserFactory)->create(ParserFactory::PREFER_PHP7);
$parser = (new ParserFactory)->createForHostVersion();
$nodeFinder = new NodeFinder;

// Add name resolver
Expand Down
4 changes: 2 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
"require": {
"php": ">=7.2.9",
"composer/installers": "~1.0",
"nikic/php-parser": "^4.11.0",
"phpdocumentor/reflection-docblock": "^5.2.2"
"nikic/php-parser": "^5.6.0",
"phpdocumentor/reflection-docblock": "^5.6.2"
},
"extra": {
"installer-name": "docs",
Expand Down
39 changes: 18 additions & 21 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd"
backupGlobals="false"
colors="true"
processIsolation="false"
stopOnFailure="false"
xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/11.5/phpunit.xsd"
cacheDirectory=".phpunit.cache"
backupStaticProperties="false"
>
<testsuites>
<testsuite name="Winter Docs Test Suite">
<directory>./tests</directory>
</testsuite>
</testsuites>

<coverage>
<include>
<directory suffix=".php">classes</directory>
<file>Plugin.php</file>
</include>
</coverage>
<testsuites>
<testsuite name="Winter Docs Test Suite">
<directory>./tests</directory>
</testsuite>
</testsuites>
<source>
<include>
<directory suffix=".php">classes</directory>
<file>Plugin.php</file>
</include>
</source>
</phpunit>
23 changes: 10 additions & 13 deletions tests/classes/ApiParserTest.php
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
<?php namespace Winter\Docs\Tests\Classes;
<?php

namespace Winter\Docs\Tests\Classes;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\CoversMethod;
use PHPUnit\Framework\Attributes\TestDox;
use System\Tests\Bootstrap\TestCase;
use Winter\Docs\Classes\PHPApiParser;

/**
* @covers \Winter\Docs\Classes\PHPApiParser
* @testdox The API Parser class (\Winter\Docs\Classes\PHPApiParser)
*/
#[CoversClass(PHPApiParser::class)]
#[TestDox('The API Parser class (\Winter\Docs\Classes\PHPApiParser)')]
class ApiParserTest extends TestCase
{
protected $apiParser;
Expand All @@ -21,10 +24,7 @@ public function setUp(): void
]);
}

/**
* @covers \Winter\Docs\Classes\PHPApiParser::getPaths()
* @testdox can get the paths of all PHP files in a given codebase.
*/
#[TestDox('can get the paths of all PHP files in a given codebase.')]
public function testGetPaths()
{
$this->assertCount(7, $this->apiParser->getPaths());
Expand All @@ -44,10 +44,7 @@ public function testGetPaths()
], $filenames);
}

/**
* @covers \Winter\Docs\Classes\PHPApiParser::parse()
* @testdox can parse all PHP files and present the schema in an array.
*/
#[TestDox('can parse all PHP files and present the schema in an array..')]
public function testParse()
{
$this->apiParser->parse();
Expand Down
127 changes: 38 additions & 89 deletions tests/classes/BaseDocumentationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,124 +2,73 @@

namespace Winter\Docs\Tests\Classes;

use PHPUnit\Framework\Attributes\CoversClass;
use PHPUnit\Framework\Attributes\TestDox;
use System\Tests\Bootstrap\TestCase;
use Winter\Docs\Classes\BaseDocumentation;
use Winter\Storm\Exception\ApplicationException;

/**
* @covers \Winter\Docs\Classes\BaseDocumentation
* @testdox The Base Documentation abstract (\Winter\Docs\Classes\BaseDocumentation)
*/
#[CoversClass(\Winter\Docs\Classes\BaseDocumentation::class)]
#[TestDox('The Base Documentation abstract (\Winter\Docs\Classes\BaseDocumentation)')]
class BaseDocumentationTest extends TestCase
{
/**
* @covers \Winter\Docs\Classes\BaseDocumentation::download()
* @covers \Winter\Docs\Classes\BaseDocumentation::isDownloaded()
* @testdox can download a remote documentation ZIP file and indicate that it is downloaded.
*/
public function testDownload(): void
#[TestDox('can download, extract a downloaded docs ZIP file and clean-up afterwards.')]
public function testDownloadExtractAndCleanUp(): void
{
$doc = $this->getMockForAbstractClass(
'Winter\Docs\Classes\BaseDocumentation',
[
$doc = $this->getMockBuilder(BaseDocumentation::class)
->setConstructorArgs([
'Winter.Docs.Test',
[
'name' => 'Winter Docs Test',
'type' => 'user',
'type' => 'md',
'source' => 'remote',
'url' => 'https://github.com/wintercms/docs/archive/refs/heads/main.zip',
'zipFolder' => 'docs-main',
]
]
);
'url' => 'https://github.com/wintercms/docs/archive/refs/heads/develop.zip',
'zipFolder' => 'docs-develop',
],
])
->onlyMethods(['process', 'getPageList'])
->getMock();

$doc->download();

$this->assertFileExists($doc->getDownloadPath('archive.zip'));
$this->assertTrue($doc->isDownloaded());
}

/**
* @covers \Winter\Docs\Classes\BaseDocumentation::download()
* @testdox will throw an exception if the documentation URL is invalid when downloading.
*/
public function testDownloadInvalidUrl(): void
{
$this->expectException(ApplicationException::class);
$this->expectExceptionMessageMatches('/Could not retrieve the documentation/i');
$doc->extract();

$doc = $this->getMockForAbstractClass(
'Winter\Docs\Classes\BaseDocumentation',
[
'Winter.Docs.Test',
[
'name' => 'Winter Docs Test',
'type' => 'md',
'source' => 'remote',
'url' => 'https://wintercms.com/missing/docs.zip',
'zipFolder' => 'docs-main',
]
]
);
$this->assertDirectoryExists($doc->getDownloadPath('collated'));
$this->assertFileExists($doc->getDownloadPath('collated/snowboard/introduction.md'));

// Re-download the file
$doc->download();
}

/**
* @covers \Winter\Docs\Classes\BaseDocumentation::extract()
* @testdox can extract a downloaded docs ZIP file.
*/
public function testExtract(): void
{
$doc = $this->getMockForAbstractClass(
'Winter\Docs\Classes\BaseDocumentation',
[
'Winter.Docs.Test',
[
'name' => 'Winter Docs Test',
'type' => 'md',
'source' => 'remote',
'url' => 'https://github.com/wintercms/docs/archive/refs/heads/develop.zip',
'zipFolder' => 'docs-develop',
]
]
);

$doc->download();
$doc->extract();
// Clean up
$doc->cleanupDownload();

$this->assertDirectoryExists($doc->getDownloadPath('collated'));
$this->assertFileExists($doc->getDownloadPath('collated/snowboard/introduction.md'));
$this->assertFileDoesNotExist($doc->getDownloadPath('archive.zip'));
$this->assertDirectoryDoesNotExist($doc->getDownloadPath('extracted'));
}

/**
* @covers \Winter\Docs\Classes\BaseDocumentation::cleanupDownload()
* @testdox can clean up downloaded and extracted assets.
*/
public function testCleanupDownload(): void
#[TestDox('will throw an exception if the documentation URL is invalid when downloading.')]
public function testDownloadInvalidUrl(): void
{
$doc = $this->getMockForAbstractClass(
'Winter\Docs\Classes\BaseDocumentation',
[
$this->expectException(ApplicationException::class);
$this->expectExceptionMessageMatches('/Could not retrieve the documentation/i');

$doc = $this->getMockBuilder(BaseDocumentation::class)
->setConstructorArgs([
'Winter.Docs.Test',
[
'name' => 'Winter Docs Test',
'type' => 'md',
'source' => 'remote',
'url' => 'https://github.com/wintercms/docs/archive/refs/heads/develop.zip',
'zipFolder' => 'docs-develop',
]
]
);

$doc->download();
$doc->extract();
'url' => 'https://wintercms.com/missing/docs.zip',
'zipFolder' => 'docs-main',
],
])
->onlyMethods(['process', 'getPageList'])
->getMock();

// Re-download the file
$doc->download();

// Clean up
$doc->cleanupDownload();

$this->assertFileDoesNotExist($doc->getDownloadPath('archive.zip'));
$this->assertDirectoryDoesNotExist($doc->getDownloadPath('extracted'));
}
}
Loading