Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HydePHP v1.8.0 - 2025-01-XX #690

Draft
wants to merge 54 commits into
base: master
Choose a base branch
from
Draft
Changes from 1 commit
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
7b712ca
Merge pull request #1791 from hydephp/automatic-serialization-method
invalid-email-address Jul 6, 2024
248732d
Merge pull request #1793 from hydephp/automatic-serialization-method
invalid-email-address Jul 6, 2024
54c52b6
Merge pull request #1794 from hydephp/prepare-post-author-changes
invalid-email-address Jul 6, 2024
f06d598
Merge pull request #1795 from hydephp/prepare-post-author-changes
invalid-email-address Jul 6, 2024
17e10bb
Merge pull request #1796 from hydephp/improve-static-analysis
invalid-email-address Jul 7, 2024
0bce45c
Merge pull request #1808 from hydephp/update-testing-helpers
invalid-email-address Jul 8, 2024
fe1b575
Merge pull request #1811 from hydephp/update-phpstorm-configuration
invalid-email-address Jul 8, 2024
a368f0b
Merge pull request #1820 from hydephp/normalize-documented-link
invalid-email-address Jul 10, 2024
0a0f107
Merge pull request #1823 from hydephp/add-new-hydestan-rules
invalid-email-address Jul 10, 2024
48ad935
Merge pull request #1829 from hydephp/blade-view-formatting
invalid-email-address Jul 11, 2024
4df8264
Merge pull request #1832 from hydephp/remove-extra-space-from-signature
invalid-email-address Jul 12, 2024
01df8b0
Merge pull request #1867 from hydephp/serve-command-test
invalid-email-address Jul 17, 2024
d744fa8
Merge pull request #1868 from hydephp/increase-type-coverage
invalid-email-address Jul 17, 2024
1720b24
Merge pull request #1879 from hydephp/hide-the-torchlight-install-com…
invalid-email-address Jul 23, 2024
0c8ddd0
Merge pull request #1880 from hydephp/fix-404-home-page-link
invalid-email-address Jul 23, 2024
163e69e
Merge pull request #1881 from hydephp/register-hidden-cache-clear-com…
invalid-email-address Jul 23, 2024
2dd5498
Merge pull request #1882 from hydephp/normalize-protocol-relative-url…
invalid-email-address Jul 23, 2024
ef20271
Clarify code comment https://github.com/hydephp/develop/commit/4546ca…
invalid-email-address Jul 23, 2024
69f8b7b
Merge pull request #1885 from hydephp/cleanup-canonical-page-helper-m…
invalid-email-address Jul 23, 2024
19ce2ed
Merge pull request #1884 from hydephp/support-setting-root-page-meta-…
invalid-email-address Jul 23, 2024
0c5f951
Merge pull request #1886 from hydephp/code-cleanup
invalid-email-address Jul 23, 2024
b136f9b
Merge pull request #1889 from hydephp/fix-hardcoded-metadata-url-asse…
invalid-email-address Jul 23, 2024
d28f9db
Update deprecation notice
invalid-email-address Jul 23, 2024
a6dbe0d
Framework version v1.7.3 https://github.com/hydephp/develop/commit/95…
invalid-email-address Jul 23, 2024
3f576ab
Merge pull request #1892 from hydephp/homepage-view-tests
invalid-email-address Jul 24, 2024
e7582a4
Merge pull request #1899 from hydephp/documentaiton-code-cleanup
invalid-email-address Jul 24, 2024
affcf3b
Merge pull request #1912 from hydephp/improve-helper-function-documen…
invalid-email-address Jul 26, 2024
cda69fa
Merge pull request #1919 from hydephp/hyde-facade-mixins
invalid-email-address Jul 28, 2024
ce0e7cb
Merge pull request #1958 from hydephp/test-cleanup
invalid-email-address Sep 8, 2024
a50d074
Merge pull request #1960 from hydephp/test-cleanup
invalid-email-address Sep 10, 2024
a8ed755
Merge pull request #1962 from hydephp/test-cleanup
invalid-email-address Sep 10, 2024
d8f5d4e
Merge pull request #1993 from hydephp/deprecate-hyde-media-link-in-fa…
invalid-email-address Nov 5, 2024
9b4b23a
Merge pull request #2005 from hydephp/improved-printed-documentation-…
invalid-email-address Nov 7, 2024
346e040
Merge pull request #2017 from hydephp/shorter-server-start-message
invalid-email-address Nov 12, 2024
f40ce6d
Merge pull request #2019 from hydephp/update-realtime-compiler-docume…
invalid-email-address Nov 14, 2024
cba3685
Link to Laravel News post https://github.com/hydephp/develop/commit/0…
invalid-email-address Dec 3, 2024
e703c7a
Compress single line annotation formatting https://github.com/hydephp…
invalid-email-address Dec 8, 2024
98a23ca
Merge pull request #2064 from hydephp/replace-glob-brace
invalid-email-address Dec 19, 2024
af9169d
Merge test runner changes into develop branch
caendesilva Dec 21, 2024
e6790c0
Merge pull request #2068 from hydephp/framework-v1.7.4
caendesilva Dec 21, 2024
b53b92a
Merge branch 'master' into develop
caendesilva Dec 21, 2024
158fe97
Merge helper script changes into develop branch
caendesilva Dec 21, 2024
82dd89b
Commit message must be checked first for some reason
caendesilva Dec 21, 2024
9529ef0
Refactor and cleanup script
caendesilva Dec 21, 2024
aafa6c0
Pretendable script
caendesilva Dec 21, 2024
af3fb84
Cleanup and make output easier to copy
caendesilva Dec 21, 2024
573b00a
Fix undefined array key
caendesilva Dec 21, 2024
3790552
Generate automatic command
caendesilva Dec 21, 2024
d4e234d
Merge branch 'master' into develop
caendesilva Dec 21, 2024
6d3207b
Merge branch 'master' into develop
caendesilva Dec 21, 2024
a9c7e9f
Merge pull request #2070 from hydephp/internationalization
caendesilva Dec 22, 2024
4bb256a
Merge branch 'master' into develop
caendesilva Dec 22, 2024
c72f11d
Framework version v1.7.5 https://github.com/hydephp/develop/commit/ad…
caendesilva Dec 22, 2024
5b96d09
Merge branch 'master' into develop
caendesilva Dec 22, 2024
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
Prev Previous commit
Next Next commit
Merge pull request #2064 from hydephp/replace-glob-brace
[1.x] Replace `GLOB_BRACE` with a more robust solution hydephp/develop@0d1280c
github-actions committed Dec 19, 2024
commit 98a23cab6e903232f76c09e55cd8c4386284e008
15 changes: 15 additions & 0 deletions src/Facades/Filesystem.php
Original file line number Diff line number Diff line change
@@ -69,6 +69,21 @@ public static function smartGlob(string $pattern, int $flags = 0): Collection
return self::kernel()->filesystem()->smartGlob($pattern, $flags);
}

/**
* Find files in the project's directory, with optional filtering by extension and recursion.
*
* The returned collection will be a list of paths relative to the project root.
*
* @param string $directory
* @param string|array<string>|false $matchExtensions The file extension(s) to match, or false to match all files.
* @param bool $recursive Whether to search recursively or not.
* @return \Illuminate\Support\Collection<int, string>
*/
public static function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection
{
return self::kernel()->filesystem()->findFiles($directory, $matchExtensions, $recursive);
}

/**
* Touch one or more files in the project's directory.
*
2 changes: 1 addition & 1 deletion src/Foundation/Kernel/FileCollection.php
Original file line number Diff line number Diff line change
@@ -59,7 +59,7 @@ protected function runExtensionHandlers(): void
protected function discoverFilesFor(string $pageClass): void
{
// Scan the source directory, and directories therein, for files that match the model's file extension.
foreach (Filesystem::smartGlob($pageClass::sourcePath('{*,**/*}'), GLOB_BRACE) as $path) {
foreach (Filesystem::findFiles($pageClass::sourceDirectory(), $pageClass::fileExtension(), true) as $path) {
if (! str_starts_with(basename((string) $path), '_')) {
$this->addFile(SourceFile::make($path, $pageClass));
}
13 changes: 13 additions & 0 deletions src/Foundation/Kernel/Filesystem.php
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
use Hyde\Foundation\HydeKernel;
use Hyde\Foundation\PharSupport;
use Illuminate\Support\Collection;
use Hyde\Framework\Actions\Internal\FileFinder;

use function collect;
use function Hyde\normalize_slashes;
@@ -183,4 +184,16 @@ public function smartGlob(string $pattern, int $flags = 0): Collection

return $files->map(fn (string $path): string => $this->pathToRelative($path));
}

/**
* @param string|array<string>|false $matchExtensions
* @return \Illuminate\Support\Collection<int, string>
*/
public function findFiles(string $directory, string|array|false $matchExtensions = false, bool $recursive = false): Collection
{
/** @var \Hyde\Framework\Actions\Internal\FileFinder $finder */
$finder = app(FileFinder::class);

return $finder->handle($directory, $matchExtensions, $recursive);
}
}
66 changes: 66 additions & 0 deletions src/Framework/Actions/Internal/FileFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

declare(strict_types=1);

namespace Hyde\Framework\Actions\Internal;

use Hyde\Facades\Filesystem;
use Hyde\Hyde;
use Illuminate\Support\Collection;
use SplFileInfo;
use Symfony\Component\Finder\Finder;

/**
* @interal This class is used internally by the framework and is not part of the public API, unless that is requested on GitHub with a valid use case.
*/
class FileFinder
{
/**
* @param array<string>|string|false $matchExtensions
* @return \Illuminate\Support\Collection<int, string>
*/
public static function handle(string $directory, array|string|false $matchExtensions = false, bool $recursive = false): Collection
{
if (! Filesystem::isDirectory($directory)) {
return collect();
}

$finder = Finder::create()->files()->in(Hyde::path($directory));

if ($recursive === false) {
$finder->depth('== 0');
}

if ($matchExtensions !== false) {
$finder->name(static::buildFileExtensionPattern((array) $matchExtensions));
}

return collect($finder)->map(function (SplFileInfo $file): string {
return Hyde::pathToRelative($file->getPathname());
})->sort()->values();
}

/** @param array<string> $extensions */
protected static function buildFileExtensionPattern(array $extensions): string
{
$extensions = self::expandCommaSeparatedValues($extensions);

return '/\.('.self::normalizeExtensionForRegexPattern($extensions).')$/i';
}

/** @param array<string> $extensions */
private static function expandCommaSeparatedValues(array $extensions): array
{
return array_merge(...array_map(function (string $item): array {
return array_map(fn (string $item): string => trim($item), explode(',', $item));
}, $extensions));
}

/** @param array<string> $extensions */
private static function normalizeExtensionForRegexPattern(array $extensions): string
{
return implode('|', array_map(function (string $extension): string {
return preg_quote(ltrim($extension, '.'), '/');
}, $extensions));
}
}
3 changes: 1 addition & 2 deletions src/Framework/Actions/PreBuildTasks/CleanSiteDirectory.php
Original file line number Diff line number Diff line change
@@ -10,7 +10,6 @@
use Hyde\Framework\Features\BuildTasks\PreBuildTask;

use function basename;
use function glob;
use function in_array;
use function sprintf;

@@ -21,7 +20,7 @@ class CleanSiteDirectory extends PreBuildTask
public function handle(): void
{
if ($this->isItSafeToCleanOutputDirectory()) {
Filesystem::unlink(glob(Hyde::sitePath('*.{html,json}'), GLOB_BRACE));
Filesystem::unlink(Filesystem::findFiles(Hyde::sitePath(), ['html', 'json'])->all());
Filesystem::cleanDirectory(Hyde::siteMediaPath());
}
}
7 changes: 2 additions & 5 deletions src/Support/DataCollections.php
Original file line number Diff line number Diff line change
@@ -12,9 +12,8 @@
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

use function implode;
use function Hyde\path_join;
use function json_decode;
use function sprintf;
use function Hyde\unslash;
use function str_starts_with;

@@ -102,9 +101,7 @@ public static function json(string $name, bool $asArray = false): static

protected static function findFiles(string $name, array|string $extensions): Collection
{
return Filesystem::smartGlob(sprintf('%s/%s/*.{%s}',
static::$sourceDirectory, $name, implode(',', (array) $extensions)
), GLOB_BRACE);
return Filesystem::findFiles(path_join(static::$sourceDirectory, $name), $extensions);
}

protected static function makeIdentifier(string $path): string
17 changes: 9 additions & 8 deletions src/Support/Filesystem/MediaFile.php
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@

namespace Hyde\Support\Filesystem;

use Hyde\Facades\Filesystem;
use Hyde\Hyde;
use Hyde\Facades\Config;
use Hyde\Framework\Exceptions\FileNotFoundException;
@@ -14,12 +15,9 @@
use function array_merge;
use function array_keys;
use function filesize;
use function implode;
use function pathinfo;
use function collect;
use function is_file;
use function sprintf;
use function glob;

/**
* File abstraction for a project media file.
@@ -104,15 +102,18 @@ protected static function discoverMediaAssetFiles(): array
})->all();
}

/** @return array<string> */
protected static function getMediaAssetFiles(): array
{
return glob(Hyde::path(static::getMediaGlobPattern()), GLOB_BRACE) ?: [];
return Filesystem::findFiles(Hyde::getMediaDirectory(), static::getMediaFileExtensions(), true)->all();
}

protected static function getMediaGlobPattern(): string
/** @return array<string>|string */
protected static function getMediaFileExtensions(): array|string
{
return sprintf(Hyde::getMediaDirectory().'/{*,**/*,**/*/*}.{%s}', implode(',',
Config::getArray('hyde.media_extensions', self::EXTENSIONS)
));
/** @var array<string>|string $config */
$config = Config::get('hyde.media_extensions', self::EXTENSIONS);

return $config;
}
}
2 changes: 1 addition & 1 deletion tests/Feature/DiscoveryServiceTest.php
Original file line number Diff line number Diff line change
@@ -130,7 +130,7 @@ public function testMediaAssetExtensionsCanBeAddedByCommaSeparatedValues()

$this->assertSame([], MediaFile::files());

self::mockConfig(['hyde.media_extensions' => ['1,2,3']]);
self::mockConfig(['hyde.media_extensions' => '1,2,3']);
$this->assertSame(['test.1', 'test.2', 'test.3'], MediaFile::files());
}

16 changes: 16 additions & 0 deletions tests/Feature/FileCollectionTest.php
Original file line number Diff line number Diff line change
@@ -106,4 +106,20 @@ public function testDocumentationPagesAreDiscovered()
$this->assertArrayHasKey('_docs/foo.md', $collection->toArray());
$this->assertEquals(new SourceFile('_docs/foo.md', DocumentationPage::class), $collection->get('_docs/foo.md'));
}

public function testDiscoverFilesForRecursivelyDiscoversFilesInSubdirectories()
{
$this->file('_pages/foo.md');
$this->file('_pages/foo/bar.md');
$this->file('_pages/foo/bar/baz.md');
$collection = FileCollection::init(Hyde::getInstance())->boot();

$this->assertArrayHasKey('_pages/foo.md', $collection->toArray());
$this->assertArrayHasKey('_pages/foo/bar.md', $collection->toArray());
$this->assertArrayHasKey('_pages/foo/bar/baz.md', $collection->toArray());

$this->assertEquals(new SourceFile('_pages/foo.md', MarkdownPage::class), $collection->get('_pages/foo.md'));
$this->assertEquals(new SourceFile('_pages/foo/bar.md', MarkdownPage::class), $collection->get('_pages/foo/bar.md'));
$this->assertEquals(new SourceFile('_pages/foo/bar/baz.md', MarkdownPage::class), $collection->get('_pages/foo/bar/baz.md'));
}
}
82 changes: 82 additions & 0 deletions tests/Feature/Foundation/FilesystemTest.php
Original file line number Diff line number Diff line change
@@ -7,22 +7,28 @@
use Hyde\Foundation\HydeKernel;
use Hyde\Foundation\Kernel\Filesystem;
use Hyde\Foundation\PharSupport;
use Hyde\Framework\Actions\Internal\FileFinder;
use Hyde\Hyde;
use Hyde\Pages\BladePage;
use Hyde\Pages\DocumentationPage;
use Hyde\Pages\HtmlPage;
use Hyde\Pages\MarkdownPage;
use Hyde\Pages\MarkdownPost;
use Hyde\Testing\CreatesTemporaryFiles;
use Hyde\Testing\UnitTestCase;
use Illuminate\Support\Collection;

use function Hyde\normalize_slashes;

/**
* @covers \Hyde\Foundation\HydeKernel
* @covers \Hyde\Foundation\Kernel\Filesystem
* @covers \Hyde\Facades\Filesystem
*/
class FilesystemTest extends UnitTestCase
{
use CreatesTemporaryFiles;

protected string $originalBasePath;

protected Filesystem $filesystem;
@@ -361,4 +367,80 @@ public function testPathToRelativeHelperDoesNotModifyNonProjectPaths()
$this->assertSame(normalize_slashes($testString), Hyde::pathToRelative($testString));
}
}

public function testFindFileMethodFindsFilesInDirectory()
{
$this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']);
$files = $this->filesystem->findFiles('directory');

$this->assertCount(3, $files);
$this->assertContains('directory/apple.md', $files);
$this->assertContains('directory/banana.md', $files);
$this->assertContains('directory/cherry.md', $files);

$this->cleanUpFilesystem();
}

public function testFindFileMethodTypes()
{
$this->file('directory/apple.md');
$files = $this->filesystem->findFiles('directory');

$this->assertInstanceOf(Collection::class, $files);
$this->assertContainsOnly('int', $files->keys());
$this->assertContainsOnly('string', $files->all());
$this->assertSame('directory/apple.md', $files->first());

$this->cleanUpFilesystem();
}

public function testFindFileMethodTypesWithArguments()
{
$this->file('directory/apple.md');

$this->assertInstanceOf(Collection::class, $this->filesystem->findFiles('directory', false, false));
$this->assertInstanceOf(Collection::class, $this->filesystem->findFiles('directory', 'md', false));
$this->assertInstanceOf(Collection::class, $this->filesystem->findFiles('directory', false, true));
$this->assertInstanceOf(Collection::class, $this->filesystem->findFiles('directory', 'md', true));

$this->cleanUpFilesystem();
}

public function testFindFilesFromFilesystemFacade()
{
$this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']);
$files = \Hyde\Facades\Filesystem::findFiles('directory');

$this->assertSame(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md'], $files->sort()->values()->all());

$this->cleanUpFilesystem();
}

public function testFindFilesFromFilesystemFacadeWithArguments()
{
$this->files(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md']);

$files = \Hyde\Facades\Filesystem::findFiles('directory', 'md');
$this->assertSame(['directory/apple.md'], $files->all());

$files = \Hyde\Facades\Filesystem::findFiles('directory', false, true);
$this->assertSame(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php', 'directory/nested/dates.md'], $files->sort()->values()->all());

$this->cleanUpFilesystem();
}

public function testCanSwapOutFileFinder()
{
app()->bind(FileFinder::class, function () {
return new class
{
public static function handle(): Collection
{
return collect(['mocked']);
}
};
});

$this->assertSame(['mocked'], \Hyde\Facades\Filesystem::findFiles('directory')->toArray());
}
}
45 changes: 18 additions & 27 deletions tests/Unit/DataCollectionUnitTest.php
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@

namespace Hyde\Framework\Testing\Unit;

use Hyde\Hyde;
use Hyde\Framework\Actions\Internal\FileFinder;
use Hyde\Support\DataCollections;
use Hyde\Testing\UnitTestCase;
use Illuminate\Filesystem\Filesystem;
@@ -45,18 +45,9 @@ public function testCanConvertCollectionToJson()
$this->assertSame('[]', (new DataCollections())->toJson());
}

public function testFindMarkdownFilesCallsProperGlobPattern()
{
$this->mockFilesystemFacade(['shouldReceiveGlob' => true]);

DataCollections::markdown('foo')->keys()->toArray();

$this->verifyMockeryExpectations();
}

public function testFindMarkdownFilesWithNoFiles()
{
$this->mockFilesystemFacade();
$this->mockFileFinder([]);

$this->assertSame([], DataCollections::markdown('foo')->keys()->toArray());

@@ -65,7 +56,7 @@ public function testFindMarkdownFilesWithNoFiles()

public function testFindMarkdownFilesWithFiles()
{
$this->mockFilesystemFacade(['glob' => ['bar.md']]);
$this->mockFileFinder(['bar.md']);

$this->assertSame(['bar.md'], DataCollections::markdown('foo')->keys()->toArray());

@@ -77,25 +68,25 @@ public function testStaticMarkdownHelperReturnsNewDataCollectionInstance()
$this->assertInstanceOf(DataCollections::class, DataCollections::markdown('foo'));
}

protected function mockFilesystemFacade(array $config = []): void
protected function mockFileFinder(array $files): void
{
$defaults = [
'exists' => true,
'glob' => [],
'get' => 'foo',
];
$filesystem = Mockery::mock(Filesystem::class);
$filesystem->shouldReceive('exists')->andReturn(true);
$filesystem->shouldReceive('get')->andReturn('foo');

$config = array_merge($defaults, $config);
app()->instance(Filesystem::class, $filesystem);

$filesystem = Mockery::mock(Filesystem::class, $config);
$finder = Mockery::mock(FileFinder::class);
$finder->shouldReceive('handle')->andReturn(collect($files));

if (isset($config['shouldReceiveGlob'])) {
$filesystem->shouldReceive('glob')
->with(Hyde::path('resources/collections/foo/*.{md}'), GLOB_BRACE)
->once()
->andReturn($config['glob']);
}
app()->instance(FileFinder::class, $finder);
}

app()->instance(Filesystem::class, $filesystem);
protected function verifyMockeryExpectations(): void
{
parent::verifyMockeryExpectations();

app()->forgetInstance(Filesystem::class);
app()->forgetInstance(FileFinder::class);
}
}
276 changes: 276 additions & 0 deletions tests/Unit/FileFinderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,276 @@
<?php

declare(strict_types=1);

namespace Hyde\Framework\Testing\Unit;

use Hyde\Hyde;
use Hyde\Testing\UnitTestCase;
use Hyde\Testing\CreatesTemporaryFiles;
use Hyde\Foundation\Kernel\Filesystem;

/**
* @covers \Hyde\Framework\Actions\Internal\FileFinder
*/
class FileFinderTest extends UnitTestCase
{
use CreatesTemporaryFiles;

protected static bool $needsKernel = true;

public function testFindFiles()
{
$this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']);
$this->assertSameArray(['apple.md', 'banana.md', 'cherry.md'], 'directory');
}

public function testFindFilesWithMixedExtensions()
{
$this->files(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php']);
$this->assertSameArray(['apple.md', 'banana.txt', 'cherry.blade.php'], 'directory');
}

public function testFindFilesWithExtension()
{
$this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md']);
$this->assertSameArray(['apple.md', 'banana.md', 'cherry.md'], 'directory', 'md');
}

public function testFindFilesWithMixedExtensionsReturnsOnlySpecifiedExtension()
{
$this->files(['directory/apple.md', 'directory/banana.txt', 'directory/cherry.blade.php']);
$this->assertSameArray(['apple.md'], 'directory', 'md');
}

public function testFindFilesWithRecursive()
{
$this->files(['directory/apple.md', 'directory/banana.md', 'directory/cherry.md', 'directory/nested/dates.md']);
$this->assertSameArray(['apple.md', 'banana.md', 'cherry.md', 'nested/dates.md'], 'directory', false, true);
}

public function testFindFilesWithDeeplyRecursiveFiles()
{
$this->files(['directory/apple.md', 'directory/nested/banana.md', 'directory/nested/deeply/cherry.md']);
$this->assertSameArray(['apple.md', 'nested/banana.md', 'nested/deeply/cherry.md'], 'directory', false, true);
}

public function testFindFilesWithVeryDeeplyRecursiveFiles()
{
$this->files(['directory/apple.md', 'directory/nested/banana.md', 'directory/nested/deeply/cherry.md', 'directory/nested/very/very/deeply/dates.md', 'directory/nested/very/very/excessively/deeply/elderberries.md']);
$this->assertSameArray(['apple.md', 'nested/banana.md', 'nested/deeply/cherry.md', 'nested/very/very/deeply/dates.md', 'nested/very/very/excessively/deeply/elderberries.md'], 'directory', false, true);
}

public function testFindFilesIgnoresNestedFilesIfNotRecursive()
{
$this->files(['directory/apple.md', 'directory/nested/banana.md', 'directory/nested/deeply/cherry.md']);
$this->assertSameArray(['apple.md'], 'directory');
}

public function testFindFilesReturnsCorrectFilesWhenUsingNestedSubdirectoriesOfDifferentExtensions()
{
$this->files(['directory/apple.md', 'directory/nested/banana.md', 'directory/nested/deeply/cherry.blade.php']);
$this->assertSameArray(['apple.md', 'nested/banana.md'], 'directory', 'md', true);
}

public function testFindFilesWithFilesHavingNoExtensions()
{
$this->files(['directory/file', 'directory/another_file']);
$this->assertSameArray(['file', 'another_file'], 'directory');
}

public function testFindFilesWithSpecialCharactersInNames()
{
$this->files(['directory/file-with-dash.md', 'directory/another_file.txt', 'directory/special@char!.blade.php']);
$this->assertSameArray(['file-with-dash.md', 'another_file.txt', 'special@char!.blade.php'], 'directory');
}

public function testFindFilesWithSpecialPrefixes()
{
$this->files(['directory/_file.md', 'directory/-another_file.txt', 'directory/~special_file.blade.php']);
$this->assertSameArray(['_file.md', '-another_file.txt', '~special_file.blade.php'], 'directory');
}

public function testFindFilesWithHiddenFiles()
{
$this->files(['directory/.hidden_file', 'directory/.another_hidden.md', 'directory/visible_file.md']);
$this->assertSameArray(['visible_file.md'], 'directory');
}

public function testFindFilesWithRecursiveAndHiddenFiles()
{
$this->files(['directory/.hidden_file', 'directory/nested/.another_hidden.md', 'directory/nested/visible_file.md']);
$this->assertSameArray(['nested/visible_file.md'], 'directory', false, true);
}

public function testFindFilesWithEmptyExtensionFilter()
{
$this->files(['directory/file.md', 'directory/another_file.txt']);
$this->assertSameArray([], 'directory', '');
}

public function testFindFilesWithCaseInsensitiveExtensions()
{
$this->files(['directory/file.MD', 'directory/another_file.md', 'directory/ignored.TXT']);
$this->assertSameArray(['file.MD', 'another_file.md'], 'directory', 'md');
}

public function testFindFilesWithCaseInsensitiveFilenames()
{
$this->files(['directory/file.md', 'directory/anotherFile.md', 'directory/ANOTHER_FILE.md']);
$this->assertSameArray(['file.md', 'anotherFile.md', 'ANOTHER_FILE.md'], 'directory');
}

public function testFindFilesWithCaseInsensitiveExtensionFilter()
{
$this->files(['directory/file.MD', 'directory/another_file.md', 'directory/ignored.TXT']);
$this->assertSameArray(['file.MD', 'another_file.md'], 'directory', 'MD');
}

public function testFindFilesWithLeadingDotInFileExtension()
{
$this->files(['directory/file.md', 'directory/another_file.md', 'directory/ignored.txt']);
$this->assertSameArray(['file.md', 'another_file.md'], 'directory', 'md');
$this->assertSameArray(['file.md', 'another_file.md'], 'directory', '.md');
}

public function testFindFilesHandlesLargeNumberOfFiles()
{
$this->files(array_map(fn ($i) => "directory/file$i.md", range(1, 100)));
$this->assertSameArray(array_map(fn ($i) => "file$i.md", range(1, 100)), 'directory');
}

public function testFindFilesWithEmptyDirectory()
{
$this->directory('directory');
$this->assertSameArray([], 'directory');
}

public function testFindFilesWithNonExistentDirectory()
{
$this->assertSameArray([], 'nonexistent-directory');
}

public function testFindFilesWithMultipleExtensions()
{
$this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.blade.php']);
$this->assertSameArray(['file1.md', 'file2.txt'], 'directory', ['md', 'txt']);
}

public function testFindFilesWithMultipleExtensionsButOnlyOneMatches()
{
$this->files(['directory/file1.md', 'directory/file2.blade.php', 'directory/file3.blade.php']);
$this->assertSameArray(['file1.md'], 'directory', ['md', 'txt']);
}

public function testFindFilesWithMultipleExtensionsCaseInsensitive()
{
$this->files(['directory/file1.MD', 'directory/file2.TXT', 'directory/file3.blade.PHP']);
$this->assertSameArray(['file1.MD', 'file2.TXT'], 'directory', ['md', 'txt']);
}

public function testFindFilesWithEmptyArrayExtensions()
{
$this->files(['directory/file1.md', 'directory/file2.txt']);
$this->assertSameArray([], 'directory', []);
}

public function testFindFilesWithMixedExtensionsAndRecursion()
{
$this->files(['directory/file1.md', 'directory/nested/file2.txt', 'directory/nested/deep/file3.blade.php']);
$this->assertSameArray(['file1.md', 'nested/file2.txt'], 'directory', ['md', 'txt'], true);
}

public function testFindFilesWithMixedExtensionsNoRecursion()
{
$this->files(['directory/file1.md', 'directory/nested/file2.txt']);
$this->assertSameArray(['file1.md'], 'directory', ['md', 'txt'], false);
}

public function testFindFilesWithNoFilesMatchingAnyExtension()
{
$this->files(['directory/file1.md', 'directory/file2.txt']);
$this->assertSameArray([], 'directory', ['php', 'html']);
}

public function testFindFilesWithRecursiveAndNoFilesMatchingAnyExtension()
{
$this->files(['directory/file1.md', 'directory/nested/file2.txt']);
$this->assertSameArray([], 'directory', ['php', 'html'], true);
}

public function testFindFilesWithRecursiveAndSomeMatchingExtensions()
{
$this->files(['directory/file1.md', 'directory/nested/file2.txt', 'directory/nested/deep/file3.html']);
$this->assertSameArray(['file1.md', 'nested/file2.txt'], 'directory', ['md', 'txt'], true);
}

public function testFindFilesWithOnlyDotInExtensions()
{
$this->files(['directory/file.md', 'directory/file.txt']);
$this->assertSameArray(['file.md'], 'directory', '.md');
$this->assertSameArray(['file.txt'], 'directory', '.txt');
}

public function testFindFilesWithNoFilesWhenDirectoryContainsUnmatchedExtensions()
{
$this->files(['directory/file.md', 'directory/file.txt']);
$this->assertSameArray([], 'directory', 'php');
$this->assertSameArray([], 'directory', ['php']);
}

public function testFindFilesWithEmptyDirectoryAndMultipleExtensions()
{
$this->directory('directory');
$this->assertSameArray([], 'directory', ['md', 'txt']);
}

public function testFindFilesWithInvalidExtensionsThrowsNoError()
{
$this->files(['directory/file.md', 'directory/file.txt']);
$this->assertSameArray([], 'directory', '');
$this->assertSameArray([], 'directory', ['']);
}

public function testFindFilesWithCsvStringExtensions()
{
$this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.jpg']);
$this->assertSameArray(['file1.md', 'file2.txt'], 'directory', 'md,txt');
}

public function testFindFilesWithCsvStringExtensionsAndSpaces()
{
$this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.jpg']);
$this->assertSameArray(['file1.md', 'file2.txt'], 'directory', 'md, txt');
}

public function testFindFilesWithCsvStringExtensionsMixedCase()
{
$this->files(['directory/file1.MD', 'directory/file2.TXT', 'directory/file3.jpg']);
$this->assertSameArray(['file1.MD', 'file2.TXT'], 'directory', 'md,TXT');
}

public function testFindFilesWithCsvStringExtensionsInArray()
{
$this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.jpg']);
$this->assertSameArray(['file1.md', 'file2.txt'], 'directory', ['md,txt']);
}

public function testFindFilesWithCsvStringExtensionsInMixedArray()
{
$this->files(['directory/file1.md', 'directory/file2.txt', 'directory/file3.jpg']);
$this->assertSameArray(['file1.md', 'file2.txt', 'file3.jpg'], 'directory', ['md,txt', 'jpg']);
}

protected function assertSameArray(array $expected, string $directory, string|array|false $matchExtensions = false, bool $recursive = false): void
{
$files = (new Filesystem(Hyde::getInstance()))->findFiles($directory, $matchExtensions, $recursive);

// Compare sorted arrays because some filesystems may return files in a different order.
$this->assertSame(collect($expected)->map(fn (string $file): string => $directory.'/'.$file)->sort()->values()->all(), $files->all());
}

protected function tearDown(): void
{
$this->cleanUpFilesystem();
}
}
88 changes: 0 additions & 88 deletions tests/Unit/Pages/PageModelGetAllFilesHelperTest.php

This file was deleted.

115 changes: 115 additions & 0 deletions tests/Unit/Pages/PageModelGetFileHelpersTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
<?php

declare(strict_types=1);

namespace Hyde\Framework\Testing\Unit\Pages;

use Hyde\Foundation\HydeKernel;
use Hyde\Pages\BladePage;
use Hyde\Testing\CreatesTemporaryFiles;
use Hyde\Testing\UnitTestCase;
use Hyde\Pages\DocumentationPage;
use Hyde\Pages\MarkdownPage;
use Hyde\Pages\MarkdownPost;
use Illuminate\Support\Collection;

class PageModelGetFileHelpersTest extends UnitTestCase
{
use CreatesTemporaryFiles;

protected static bool $needsKernel = true;
protected static bool $needsConfig = true;

public function testBladePageFilesHelperReturnsBladePageArray()
{
$this->withFile('_pages/test-page.blade.php');

$array = BladePage::files();
$this->assertCount(3, $array);
$this->assertIsArray($array);
$this->assertEquals(['404', 'index', 'test-page'], $array);
}

public function testMarkdownPageFilesHelperReturnsMarkdownPageArray()
{
$this->withFile('_pages/test-page.md');

$array = MarkdownPage::files();
$this->assertCount(1, $array);
$this->assertIsArray($array);
$this->assertEquals(['test-page'], $array);
}

public function testMarkdownPostFilesHelperReturnsMarkdownPostArray()
{
$this->withFile('_posts/test-post.md');

$array = MarkdownPost::files();
$this->assertCount(1, $array);
$this->assertIsArray($array);
$this->assertEquals(['test-post'], $array);
}

public function testDocumentationPageFilesHelperReturnsDocumentationPageArray()
{
$this->withFile('_docs/test-page.md');

$array = DocumentationPage::files();
$this->assertCount(1, $array);
$this->assertIsArray($array);
$this->assertEquals(['test-page'], $array);
}

public function testBladePageAllHelperReturnsBladePageCollection()
{
$this->withFile('_pages/test-page.blade.php');

$collection = BladePage::all();

$this->assertCount(3, $collection);
$this->assertInstanceOf(Collection::class, $collection);
$this->assertContainsOnlyInstancesOf(BladePage::class, $collection);
}

public function testMarkdownPageAllHelperReturnsMarkdownPageCollection()
{
$this->withFile('_pages/test-page.md');

$collection = MarkdownPage::all();
$this->assertCount(1, $collection);
$this->assertInstanceOf(Collection::class, $collection);
$this->assertContainsOnlyInstancesOf(MarkdownPage::class, $collection);
}

public function testMarkdownPostAllHelperReturnsMarkdownPostCollection()
{
$this->withFile('_posts/test-post.md');

$collection = MarkdownPost::all();
$this->assertCount(1, $collection);
$this->assertInstanceOf(Collection::class, $collection);
$this->assertContainsOnlyInstancesOf(MarkdownPost::class, $collection);
}

public function testDocumentationPageAllHelperReturnsDocumentationPageCollection()
{
$this->withFile('_docs/test-page.md');

$collection = DocumentationPage::all();
$this->assertCount(1, $collection);
$this->assertInstanceOf(Collection::class, $collection);
$this->assertContainsOnlyInstancesOf(DocumentationPage::class, $collection);
}

protected function withFile(string $path): void
{
$this->file($path);

HydeKernel::getInstance()->boot();
}

protected function tearDown(): void
{
$this->cleanupFilesystem();
}
}
97 changes: 0 additions & 97 deletions tests/Unit/Pages/PageModelGetHelperTest.php

This file was deleted.