From 1bdf4ba3c50c89a2e50afe567b12a5583041d796 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 14:43:11 +0200 Subject: [PATCH 01/88] Annotate the collection generics --- .../partials/hyde-pages-api/hyde-kernel-filesystem-methods.md | 4 ++-- .../framework/src/Foundation/Concerns/ForwardsFilesystem.php | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md b/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md index 55dfcdafe4b..9823b18f5f4 100644 --- a/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md +++ b/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md @@ -1,7 +1,7 @@
- + #### `filesystem()` @@ -56,7 +56,7 @@ Hyde::pathToRelative(string $path): string No description provided. ```php -Hyde::assets(): Illuminate\Support\Collection +Hyde::assets(): Collection ``` diff --git a/packages/framework/src/Foundation/Concerns/ForwardsFilesystem.php b/packages/framework/src/Foundation/Concerns/ForwardsFilesystem.php index 888f3abf4d0..1f45bc30655 100644 --- a/packages/framework/src/Foundation/Concerns/ForwardsFilesystem.php +++ b/packages/framework/src/Foundation/Concerns/ForwardsFilesystem.php @@ -44,6 +44,7 @@ public function pathToRelative(string $path): string return $this->filesystem->pathToRelative($path); } + /** @return Collection */ public function assets(): Collection { return $this->filesystem->assets(); From 96781f996026d8782f094ae95cfe465fce1d9bb5 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 15:52:08 +0200 Subject: [PATCH 02/88] Normalize implementation syntax --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 5457e18ba03..5d362d7aeb4 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -60,9 +60,7 @@ public static function outputPath(string $path = ''): string return Hyde::sitePath(Hyde::getMediaOutputDirectory()); } - $path = unslash($path); - - return Hyde::sitePath(Hyde::getMediaOutputDirectory()."/$path"); + return Hyde::sitePath(path_join(Hyde::getMediaOutputDirectory(), unslash($path))); } public function getIdentifier(): string From 27778927dd2931bed4ef5d224d4674587ff769cc Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:18:47 +0200 Subject: [PATCH 03/88] Document identifier method --- packages/framework/src/Support/Filesystem/MediaFile.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 5d362d7aeb4..d25889dff82 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -63,6 +63,9 @@ public static function outputPath(string $path = ''): string return Hyde::sitePath(path_join(Hyde::getMediaOutputDirectory(), unslash($path))); } + /** + * Get the path to the media file relative to the media directory. + */ public function getIdentifier(): string { return Str::after($this->getPath(), Hyde::getMediaDirectory().'/'); From 58cfaf85862be68470c1d0b3554583580c86169c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:18:55 +0200 Subject: [PATCH 04/88] Add more tests for the identifier method --- .../framework/tests/Unit/Support/MediaFileTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index 16f9c1477f3..0043845a48d 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -249,6 +249,16 @@ public function testGetIdentifierWithSubdirectory() $this->assertSame('foo/bar', MediaFile::make('foo/bar')->getIdentifier()); } + public function testGetIdentifierReturnsIdentifierWithFileExtension() + { + $this->assertSame('foo.png', MediaFile::make('foo.png')->getIdentifier()); + } + + public function testGetIdentifierWithSubdirectoryWithFileExtension() + { + $this->assertSame('foo/bar.png', MediaFile::make('foo/bar.png')->getIdentifier()); + } + public function testHelperForMediaPath() { $this->assertSame(Hyde::path('_media'), MediaFile::sourcePath()); From 4e4ef03dbe6f32a73790a2109c1551a08cfb4877 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:10:21 +0200 Subject: [PATCH 05/88] Override parent constructor --- packages/framework/src/Support/Filesystem/MediaFile.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index d25889dff82..4571582d1b7 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -27,6 +27,11 @@ class MediaFile extends ProjectFile /** @var array The default extensions for media types */ final public const EXTENSIONS = ['png', 'svg', 'jpg', 'jpeg', 'gif', 'ico', 'css', 'js']; + public function __construct(string $path) + { + parent::__construct($path); + } + /** @return \Illuminate\Support\Collection The array keys are the filenames relative to the _media/ directory */ public static function all(): Collection { From c8ca302ada7f561f58d4863799bca9196914b9be Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:13:50 +0200 Subject: [PATCH 06/88] Normalize stored internal path --- packages/framework/src/Support/Filesystem/MediaFile.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 4571582d1b7..55f95d6a1a7 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -12,6 +12,7 @@ use function Hyde\unslash; use function Hyde\path_join; +use function Hyde\trim_slashes; use function extension_loaded; use function file_exists; use function array_merge; @@ -29,6 +30,8 @@ class MediaFile extends ProjectFile public function __construct(string $path) { + $path = trim_slashes(Str::after($path, Hyde::getMediaDirectory())); + parent::__construct($path); } From c4b7af3c42069e7e9a553b00482f33170c3d0540 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:16:52 +0200 Subject: [PATCH 07/88] Normalize formatter syntax --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 55f95d6a1a7..525cae51fd7 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -30,7 +30,7 @@ class MediaFile extends ProjectFile public function __construct(string $path) { - $path = trim_slashes(Str::after($path, Hyde::getMediaDirectory())); + $path = Str::after($path, Hyde::getMediaDirectory().'/'); parent::__construct($path); } From b20eab63d01f6c366714ad4f99a1475741094dec Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:19:32 +0200 Subject: [PATCH 08/88] Revert "Normalize formatter syntax" This reverts commit c4b7af3c42069e7e9a553b00482f33170c3d0540. --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 525cae51fd7..55f95d6a1a7 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -30,7 +30,7 @@ class MediaFile extends ProjectFile public function __construct(string $path) { - $path = Str::after($path, Hyde::getMediaDirectory().'/'); + $path = trim_slashes(Str::after($path, Hyde::getMediaDirectory())); parent::__construct($path); } From 0907bc5c7e38752b1a9887b5e420e77ceb67096c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:20:54 +0200 Subject: [PATCH 09/88] Test normalization --- .../framework/tests/Unit/Support/MediaFileTest.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index 0043845a48d..e47e8a290b4 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -86,6 +86,16 @@ public function testAbsolutePathIsNormalizedToRelative() $this->assertSame('foo', MediaFile::make(Hyde::path('foo'))->path); } + public function testMediaPathIsNormalizedToRelative() + { + $this->assertSame('foo', MediaFile::make('_media/foo')->path); + } + + public function testAbsoluteMediaPathIsNormalizedToRelative() + { + $this->assertSame('foo', MediaFile::make(Hyde::path('_media/foo'))->path); + } + public function testGetNameReturnsNameOfFile() { $this->assertSame('foo.txt', MediaFile::make('foo.txt')->getName()); From c3b7ca8c9cd16ad51871a02cc8b9a0d459b353b4 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:24:31 +0200 Subject: [PATCH 10/88] Add initial normalization --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 55f95d6a1a7..8b375af9026 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -30,7 +30,7 @@ class MediaFile extends ProjectFile public function __construct(string $path) { - $path = trim_slashes(Str::after($path, Hyde::getMediaDirectory())); + $path = trim_slashes(Str::after(Hyde::pathToRelative($path), Hyde::getMediaDirectory())); parent::__construct($path); } From e82649c18458d451b9762f6a36b738aa8fafc0f4 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:43:57 +0200 Subject: [PATCH 11/88] Update MediaFileTest.php --- .../framework/tests/Unit/Support/MediaFileTest.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index e47e8a290b4..cf5c80dc9d3 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -81,17 +81,22 @@ public function testCanConstructWithNestedPaths() $this->assertSame('path/to/file.txt', MediaFile::make('path/to/file.txt')->path); } - public function testAbsolutePathIsNormalizedToRelative() + public function testPathIsNormalizedToRelativeMediaPath() + { + $this->assertSame('_media/foo', MediaFile::make('foo')->path); + } + + public function testAbsolutePathIsNormalizedToRelativeMediaPath() { $this->assertSame('foo', MediaFile::make(Hyde::path('foo'))->path); } - public function testMediaPathIsNormalizedToRelative() + public function testMediaPathIsNormalizedToRelativeMediaPath() { $this->assertSame('foo', MediaFile::make('_media/foo')->path); } - public function testAbsoluteMediaPathIsNormalizedToRelative() + public function testAbsoluteMediaPathIsNormalizedToRelativeMediaPath() { $this->assertSame('foo', MediaFile::make(Hyde::path('_media/foo'))->path); } From 4e9ea803122424a1dd040435dfea3db455601150 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:28:04 +0200 Subject: [PATCH 12/88] Change normalization to enforce parent documented state --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 8b375af9026..e31297c93ba 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -32,7 +32,7 @@ public function __construct(string $path) { $path = trim_slashes(Str::after(Hyde::pathToRelative($path), Hyde::getMediaDirectory())); - parent::__construct($path); + parent::__construct(static::sourcePath($path)); } /** @return \Illuminate\Support\Collection The array keys are the filenames relative to the _media/ directory */ From 82bbc1c4224f1daed697dfa53a36f73589a32a2d Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:40:50 +0200 Subject: [PATCH 13/88] Update tests to expect media file paths are normalized on construct --- .../tests/Unit/Support/MediaFileTest.php | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index cf5c80dc9d3..ec118f5b700 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -68,7 +68,7 @@ public function testCanConstruct() $file = new MediaFile('foo'); $this->assertInstanceOf(MediaFile::class, $file); - $this->assertSame('foo', $file->path); + $this->assertSame('_media/foo', $file->path); } public function testCanMake() @@ -78,7 +78,7 @@ public function testCanMake() public function testCanConstructWithNestedPaths() { - $this->assertSame('path/to/file.txt', MediaFile::make('path/to/file.txt')->path); + $this->assertSame('_media/path/to/file.txt', MediaFile::make('path/to/file.txt')->path); } public function testPathIsNormalizedToRelativeMediaPath() @@ -88,17 +88,17 @@ public function testPathIsNormalizedToRelativeMediaPath() public function testAbsolutePathIsNormalizedToRelativeMediaPath() { - $this->assertSame('foo', MediaFile::make(Hyde::path('foo'))->path); + $this->assertSame('_media/foo', MediaFile::make(Hyde::path('foo'))->path); } public function testMediaPathIsNormalizedToRelativeMediaPath() { - $this->assertSame('foo', MediaFile::make('_media/foo')->path); + $this->assertSame('_media/foo', MediaFile::make('_media/foo')->path); } public function testAbsoluteMediaPathIsNormalizedToRelativeMediaPath() { - $this->assertSame('foo', MediaFile::make(Hyde::path('_media/foo'))->path); + $this->assertSame('_media/foo', MediaFile::make(Hyde::path('_media/foo'))->path); } public function testGetNameReturnsNameOfFile() @@ -109,38 +109,38 @@ public function testGetNameReturnsNameOfFile() public function testGetPathReturnsPathOfFile() { - $this->assertSame('foo.txt', MediaFile::make('foo.txt')->getPath()); - $this->assertSame('foo/bar.txt', MediaFile::make('foo/bar.txt')->getPath()); + $this->assertSame('_media/foo.txt', MediaFile::make('foo.txt')->getPath()); + $this->assertSame('_media/foo/bar.txt', MediaFile::make('foo/bar.txt')->getPath()); } public function testGetAbsolutePathReturnsAbsolutePathOfFile() { - $this->assertSame(Hyde::path('foo.txt'), MediaFile::make('foo.txt')->getAbsolutePath()); - $this->assertSame(Hyde::path('foo/bar.txt'), MediaFile::make('foo/bar.txt')->getAbsolutePath()); + $this->assertSame(Hyde::path('_media/foo.txt'), MediaFile::make('foo.txt')->getAbsolutePath()); + $this->assertSame(Hyde::path('_media/foo/bar.txt'), MediaFile::make('foo/bar.txt')->getAbsolutePath()); } public function testGetContentsReturnsContentsOfFile() { - $this->file('foo.txt', 'foo bar'); + $this->file('_media/foo.txt', 'foo bar'); $this->assertSame('foo bar', MediaFile::make('foo.txt')->getContents()); } public function testGetExtensionReturnsExtensionOfFile() { - $this->file('foo.txt', 'foo'); + $this->file('_media/foo.txt', 'foo'); $this->assertSame('txt', MediaFile::make('foo.txt')->getExtension()); - $this->file('foo.png', 'foo'); + $this->file('_media/foo.png', 'foo'); $this->assertSame('png', MediaFile::make('foo.png')->getExtension()); } public function testToArrayReturnsArrayOfFileProperties() { - $this->file('foo.txt', 'foo bar'); + $this->file('_media/foo.txt', 'foo bar'); $this->assertSame([ 'name' => 'foo.txt', - 'path' => 'foo.txt', + 'path' => '_media/foo.txt', 'length' => 7, 'mimeType' => 'text/plain', ], MediaFile::make('foo.txt')->toArray()); @@ -148,11 +148,11 @@ public function testToArrayReturnsArrayOfFileProperties() public function testToArrayWithEmptyFileWithNoExtension() { - $this->file('foo', 'foo bar'); + $this->file('_media/foo', 'foo bar'); $this->assertSame([ 'name' => 'foo', - 'path' => 'foo', + 'path' => '_media/foo', 'length' => 7, 'mimeType' => 'text/plain', ], MediaFile::make('foo')->toArray()); @@ -160,38 +160,38 @@ public function testToArrayWithEmptyFileWithNoExtension() public function testToArrayWithFileInSubdirectory() { - mkdir(Hyde::path('foo')); - touch(Hyde::path('foo/bar.txt')); + mkdir(Hyde::path('_media/foo')); + touch(Hyde::path('_media/foo/bar.txt')); $this->assertSame([ 'name' => 'bar.txt', - 'path' => 'foo/bar.txt', + 'path' => '_media/foo/bar.txt', 'length' => 0, 'mimeType' => 'text/plain', ], MediaFile::make('foo/bar.txt')->toArray()); - Filesystem::unlink('foo/bar.txt'); - rmdir(Hyde::path('foo')); + Filesystem::unlink('_media/foo/bar.txt'); + rmdir(Hyde::path('_media/foo')); } public function testGetContentLength() { - $this->file('foo', 'Hello World!'); + $this->file('_media/foo', 'Hello World!'); $this->assertSame(12, MediaFile::make('foo')->getContentLength()); } public function testGetContentLengthWithEmptyFile() { - $this->file('foo', ''); + $this->file('_media/foo', ''); $this->assertSame(0, MediaFile::make('foo')->getContentLength()); } public function testGetContentLengthWithDirectory() { - $this->directory('foo'); + $this->directory('_media/foo'); $this->expectException(FileNotFoundException::class); - $this->expectExceptionMessage('File [foo] not found.'); + $this->expectExceptionMessage('File [_media/foo] not found.'); MediaFile::make('foo')->getContentLength(); } @@ -199,32 +199,32 @@ public function testGetContentLengthWithDirectory() public function testGetContentLengthWithNonExistentFile() { $this->expectException(FileNotFoundException::class); - $this->expectExceptionMessage('File [foo] not found.'); + $this->expectExceptionMessage('File [_media/foo] not found.'); MediaFile::make('foo')->getContentLength(); } public function testGetMimeType() { - $this->file('foo.txt', 'Hello World!'); + $this->file('_media/foo.txt', 'Hello World!'); $this->assertSame('text/plain', MediaFile::make('foo.txt')->getMimeType()); } public function testGetMimeTypeWithoutExtension() { - $this->file('foo', 'Hello World!'); + $this->file('_media/foo', 'Hello World!'); $this->assertSame('text/plain', MediaFile::make('foo')->getMimeType()); } public function testGetMimeTypeWithEmptyFile() { - $this->file('foo', ''); + $this->file('_media/foo', ''); $this->assertSame('application/x-empty', MediaFile::make('foo')->getMimeType()); } public function testGetMimeTypeWithDirectory() { - $this->directory('foo'); + $this->directory('_media/foo'); $this->assertSame('directory', MediaFile::make('foo')->getMimeType()); } From 67f056f39e2d7009e5b28c1d27858b47f1737ff5 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 16:45:40 +0200 Subject: [PATCH 14/88] Add more unit tests --- .../framework/tests/Unit/Support/MediaFileTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index ec118f5b700..3feee0d53c2 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -101,6 +101,17 @@ public function testAbsoluteMediaPathIsNormalizedToRelativeMediaPath() $this->assertSame('_media/foo', MediaFile::make(Hyde::path('_media/foo'))->path); } + public function testCustomMediaPathsAreNormalizedToRelativeCustomizedMediaPath() + { + Hyde::setMediaDirectory('bar'); + + $this->assertSame('bar/foo', MediaFile::make('foo')->path); + $this->assertSame('bar/foo', MediaFile::make('bar/foo')->path); + $this->assertSame('bar/foo', MediaFile::make(Hyde::path('foo'))->path); + + Hyde::setMediaDirectory('_media'); + } + public function testGetNameReturnsNameOfFile() { $this->assertSame('foo.txt', MediaFile::make('foo.txt')->getName()); From 9f920f71170452fc385a23f337e44a8d6c2feda3 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 17:31:35 +0200 Subject: [PATCH 15/88] Fix missing test reset --- packages/framework/tests/Unit/Support/MediaFileTest.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index 3feee0d53c2..488d95f324c 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -332,5 +332,8 @@ public function testGetSiteMediaOutputDirectoryUsesConfiguredSiteOutputDirectory Hyde::setMediaDirectory('bar'); $this->assertSame(Hyde::path('foo/bar'), MediaFile::outputPath()); + + Hyde::setOutputDirectory(Hyde::path('_site')); + Hyde::setMediaDirectory('_media'); } } From 4aa11b4b2fd8c8bb0c032074b8271bc494272fcc Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 17:06:40 +0200 Subject: [PATCH 16/88] Add hash accessor --- packages/framework/src/Support/Filesystem/MediaFile.php | 5 +++++ packages/framework/tests/Unit/Support/MediaFileTest.php | 7 +++++++ 2 files changed, 12 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index e31297c93ba..c67ab173e2a 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -128,6 +128,11 @@ public function getMimeType(): string return 'text/plain'; } + public function getHash(): string + { + return md5_file($this->getAbsolutePath()); + } + /** @internal */ public static function getCacheBustKey(string $file): string { diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index 488d95f324c..85a60d18330 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -336,4 +336,11 @@ public function testGetSiteMediaOutputDirectoryUsesConfiguredSiteOutputDirectory Hyde::setOutputDirectory(Hyde::path('_site')); Hyde::setMediaDirectory('_media'); } + + public function testGetHash() + { + $this->file('_media/foo.txt', 'Hello World!'); + + $this->assertSame(md5('Hello World!'), MediaFile::make('foo.txt')->getHash()); + } } From dca20a021d646a11cbd4b79e13c697cd85c67b5f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 20:36:32 +0200 Subject: [PATCH 17/88] Use CRC32 for media asset hashing See lengthy discussion at https://github.com/hydephp/develop/pull/1918#discussion_r1694288128 --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- packages/framework/tests/Unit/Support/MediaFileTest.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index c67ab173e2a..d7d42ead576 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -130,7 +130,7 @@ public function getMimeType(): string public function getHash(): string { - return md5_file($this->getAbsolutePath()); + return hash_file('crc32', $this->getAbsolutePath()); } /** @internal */ diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index 85a60d18330..e2000a6b370 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -341,6 +341,6 @@ public function testGetHash() { $this->file('_media/foo.txt', 'Hello World!'); - $this->assertSame(md5('Hello World!'), MediaFile::make('foo.txt')->getHash()); + $this->assertSame(hash('crc32', 'Hello World!'), MediaFile::make('foo.txt')->getHash()); } } From 4cb592f5cf0ec80f47c1b2c20a10355616d85280 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 20:51:18 +0200 Subject: [PATCH 18/88] Use CRC32 for media asset cache busting See lengthy discussion at https://github.com/hydephp/develop/pull/1918#discussion_r1694288128 --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- .../framework/tests/Feature/Foundation/HyperlinksTest.php | 4 ++-- packages/framework/tests/Unit/Facades/AssetFacadeUnitTest.php | 4 ++-- .../framework/tests/Unit/MediaDirectoryCanBeChangedTest.php | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index d7d42ead576..b2a2f76dd6d 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -137,7 +137,7 @@ public function getHash(): string public static function getCacheBustKey(string $file): string { return Config::getBool('hyde.enable_cache_busting', true) && file_exists(MediaFile::sourcePath("$file")) - ? '?v='.md5_file(MediaFile::sourcePath("$file")) + ? '?v='.hash_file('crc32', MediaFile::sourcePath("$file")) : ''; } } diff --git a/packages/framework/tests/Feature/Foundation/HyperlinksTest.php b/packages/framework/tests/Feature/Foundation/HyperlinksTest.php index 9a7893a0d6a..88fa946bf24 100644 --- a/packages/framework/tests/Feature/Foundation/HyperlinksTest.php +++ b/packages/framework/tests/Feature/Foundation/HyperlinksTest.php @@ -107,8 +107,8 @@ public function testMediaLinkHelperUsesConfiguredMediaDirectory() public function testMediaLinkHelperWithValidationAndExistingFile() { - $this->file('_media/foo'); - $this->assertSame('media/foo?v=d41d8cd98f00b204e9800998ecf8427e', $this->class->mediaLink('foo', true)); + $this->file('_media/foo', 'test'); + $this->assertSame('media/foo?v=accf8b33', $this->class->mediaLink('foo', true)); } public function testMediaLinkHelperWithValidationAndNonExistingFile() diff --git a/packages/framework/tests/Unit/Facades/AssetFacadeUnitTest.php b/packages/framework/tests/Unit/Facades/AssetFacadeUnitTest.php index 5c43956cbcf..f219a8d9318 100644 --- a/packages/framework/tests/Unit/Facades/AssetFacadeUnitTest.php +++ b/packages/framework/tests/Unit/Facades/AssetFacadeUnitTest.php @@ -49,7 +49,7 @@ public function testHasMediaFileHelperReturnsTrueForExistingFile() public function testMediaLinkReturnsMediaPathWithCacheKey() { $this->assertIsString($path = Asset::mediaLink('app.css')); - $this->assertSame('media/app.css?v='.md5_file(Hyde::path('_media/app.css')), $path); + $this->assertSame('media/app.css?v='.hash_file('crc32', Hyde::path('_media/app.css')), $path); } public function testMediaLinkReturnsMediaPathWithoutCacheKeyIfCacheBustingIsDisabled() @@ -72,6 +72,6 @@ public function testMediaLinkSupportsCustomMediaDirectories() $path = Asset::mediaLink('app.css'); $this->assertIsString($path); - $this->assertSame('assets/app.css?v='.md5_file(Hyde::path('_assets/app.css')), $path); + $this->assertSame('assets/app.css?v='.hash_file('crc32', Hyde::path('_assets/app.css')), $path); } } diff --git a/packages/framework/tests/Unit/MediaDirectoryCanBeChangedTest.php b/packages/framework/tests/Unit/MediaDirectoryCanBeChangedTest.php index f2521fc54f6..741646b4c7e 100644 --- a/packages/framework/tests/Unit/MediaDirectoryCanBeChangedTest.php +++ b/packages/framework/tests/Unit/MediaDirectoryCanBeChangedTest.php @@ -67,12 +67,12 @@ public function testCompiledPagesHaveLinksToTheRightMediaFileLocation() $this->assertFileExists(Hyde::path('_site/foo.html')); $contents = file_get_contents(Hyde::path('_site/foo.html')); $this->assertStringContainsString( - '', + '', $contents ); $this->assertStringContainsString( - '', + '', $contents ); From 9af2d815f8cbfda7758dd0d934992e5ec7e71c5b Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 21:18:10 +0200 Subject: [PATCH 19/88] Get the hash through creating an instance --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index b2a2f76dd6d..9481be80b72 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -137,7 +137,7 @@ public function getHash(): string public static function getCacheBustKey(string $file): string { return Config::getBool('hyde.enable_cache_busting', true) && file_exists(MediaFile::sourcePath("$file")) - ? '?v='.hash_file('crc32', MediaFile::sourcePath("$file")) + ? '?v='.MediaFile::make($file)->getHash() : ''; } } From 43e99aed97d4b51af73c33ec1adbad44784188c0 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 21:18:40 +0200 Subject: [PATCH 20/88] Use static to reference the same class --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 9481be80b72..7e1c540170c 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -136,8 +136,8 @@ public function getHash(): string /** @internal */ public static function getCacheBustKey(string $file): string { - return Config::getBool('hyde.enable_cache_busting', true) && file_exists(MediaFile::sourcePath("$file")) - ? '?v='.MediaFile::make($file)->getHash() + return Config::getBool('hyde.enable_cache_busting', true) && file_exists(static::sourcePath("$file")) + ? '?v='.static::make($file)->getHash() : ''; } } From 09689fbe83ae7dfccc6508cc255a6bc54f34f7a7 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sun, 28 Jul 2024 21:30:19 +0200 Subject: [PATCH 21/88] Add the hash to the array representation --- packages/framework/src/Support/Filesystem/MediaFile.php | 1 + packages/framework/tests/Feature/Foundation/FilesystemTest.php | 1 + packages/framework/tests/Unit/Support/MediaFileTest.php | 3 +++ 3 files changed, 5 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 7e1c540170c..85be0113ea4 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -84,6 +84,7 @@ public function toArray(): array return array_merge(parent::toArray(), [ 'length' => $this->getContentLength(), 'mimeType' => $this->getMimeType(), + 'hash' => $this->getHash(), ]); } diff --git a/packages/framework/tests/Feature/Foundation/FilesystemTest.php b/packages/framework/tests/Feature/Foundation/FilesystemTest.php index 01f7e83ac11..a65c92d8d67 100644 --- a/packages/framework/tests/Feature/Foundation/FilesystemTest.php +++ b/packages/framework/tests/Feature/Foundation/FilesystemTest.php @@ -377,6 +377,7 @@ public function testAssetsMethodGetsAllSiteAssetsAsArray() 'path' => '_media/app.css', 'length' => 123, 'mimeType' => 'text/css', + 'hash' => hash_file('crc32', Hyde::path('_media/app.css')), ], ], $assets); } diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index e2000a6b370..a0efbf73091 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -154,6 +154,7 @@ public function testToArrayReturnsArrayOfFileProperties() 'path' => '_media/foo.txt', 'length' => 7, 'mimeType' => 'text/plain', + 'hash' => hash('crc32', 'foo bar'), ], MediaFile::make('foo.txt')->toArray()); } @@ -166,6 +167,7 @@ public function testToArrayWithEmptyFileWithNoExtension() 'path' => '_media/foo', 'length' => 7, 'mimeType' => 'text/plain', + 'hash' => hash('crc32', 'foo bar'), ], MediaFile::make('foo')->toArray()); } @@ -179,6 +181,7 @@ public function testToArrayWithFileInSubdirectory() 'path' => '_media/foo/bar.txt', 'length' => 0, 'mimeType' => 'text/plain', + 'hash' => hash('crc32', ''), ], MediaFile::make('foo/bar.txt')->toArray()); Filesystem::unlink('_media/foo/bar.txt'); From b936744062fcf2d1620eb92d9f8471d14df95eea Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:30:10 +0200 Subject: [PATCH 22/88] Throw exception if media file does not exist --- packages/framework/src/Support/Filesystem/MediaFile.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 85be0113ea4..63b2bd22f22 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -6,6 +6,7 @@ use Hyde\Hyde; use Hyde\Facades\Config; +use Hyde\Facades\Filesystem; use Illuminate\Support\Collection; use Hyde\Framework\Exceptions\FileNotFoundException; use Illuminate\Support\Str; @@ -32,6 +33,10 @@ public function __construct(string $path) { $path = trim_slashes(Str::after(Hyde::pathToRelative($path), Hyde::getMediaDirectory())); + if (Filesystem::missing($path)) { + throw new FileNotFoundException($path); + } + parent::__construct(static::sourcePath($path)); } From b1d6f30400e24129aa2f114ab754fc97e69ef0a5 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:32:39 +0200 Subject: [PATCH 23/88] Revert "Throw exception if media file does not exist" This reverts commit b936744062fcf2d1620eb92d9f8471d14df95eea as it should not be possible for this to happen with normal usage, since we generate these based on discovered files. If a developer does something custom, we can't assume they want files backed by disk. We'll see how we handle construct time data generation though... It also makes unit testing harder (we could add an internal static property to disable validation) --- packages/framework/src/Support/Filesystem/MediaFile.php | 5 ----- 1 file changed, 5 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 63b2bd22f22..85be0113ea4 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -6,7 +6,6 @@ use Hyde\Hyde; use Hyde\Facades\Config; -use Hyde\Facades\Filesystem; use Illuminate\Support\Collection; use Hyde\Framework\Exceptions\FileNotFoundException; use Illuminate\Support\Str; @@ -33,10 +32,6 @@ public function __construct(string $path) { $path = trim_slashes(Str::after(Hyde::pathToRelative($path), Hyde::getMediaDirectory())); - if (Filesystem::missing($path)) { - throw new FileNotFoundException($path); - } - parent::__construct(static::sourcePath($path)); } From 0b77a4d42d1f57d2cd850eed48b850d52f4ee35d Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:33:31 +0200 Subject: [PATCH 24/88] Reapply "Throw exception if media file does not exist" This reverts commit b1d6f30400e24129aa2f114ab754fc97e69ef0a5 as we're going to need this sanity check to reduce complexity with construct time data generation --- packages/framework/src/Support/Filesystem/MediaFile.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 85be0113ea4..63b2bd22f22 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -6,6 +6,7 @@ use Hyde\Hyde; use Hyde\Facades\Config; +use Hyde\Facades\Filesystem; use Illuminate\Support\Collection; use Hyde\Framework\Exceptions\FileNotFoundException; use Illuminate\Support\Str; @@ -32,6 +33,10 @@ public function __construct(string $path) { $path = trim_slashes(Str::after(Hyde::pathToRelative($path), Hyde::getMediaDirectory())); + if (Filesystem::missing($path)) { + throw new FileNotFoundException($path); + } + parent::__construct(static::sourcePath($path)); } From 21340c90529c7e4335bab80c1ba9216ccab8665a Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:35:55 +0200 Subject: [PATCH 25/88] Files should receive missing and return false --- packages/framework/tests/Unit/Support/MediaFileTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index a0efbf73091..efdbe12b859 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -5,6 +5,7 @@ namespace Hyde\Framework\Testing\Unit\Support; use Hyde\Facades\Filesystem; +use Illuminate\Support\Facades\File; use Hyde\Framework\Exceptions\FileNotFoundException; use Hyde\Hyde; use Hyde\Support\Filesystem\MediaFile; @@ -21,6 +22,13 @@ class MediaFileTest extends UnitTestCase protected static bool $needsKernel = true; protected static bool $needsConfig = true; + protected function setUp(): void + { + parent::setUp(); + + File::shouldReceive('missing')->andReturn(false); + } + protected function tearDown(): void { $this->cleanUpFilesystem(); From 6e5c26106c300445470e99d0f862d354dfa61f8d Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:43:15 +0200 Subject: [PATCH 26/88] Validate the normalized path --- packages/framework/src/Support/Filesystem/MediaFile.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 63b2bd22f22..445748f9f46 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -32,12 +32,13 @@ class MediaFile extends ProjectFile public function __construct(string $path) { $path = trim_slashes(Str::after(Hyde::pathToRelative($path), Hyde::getMediaDirectory())); + $path = static::sourcePath($path); if (Filesystem::missing($path)) { throw new FileNotFoundException($path); } - parent::__construct(static::sourcePath($path)); + parent::__construct($path); } /** @return \Illuminate\Support\Collection The array keys are the filenames relative to the _media/ directory */ From 070a7ff4d73797cc21b0aa858f1e5a534ffd72dd Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:47:49 +0200 Subject: [PATCH 27/88] Refactor to use mocks --- .../tests/Unit/Support/MediaFileTest.php | 40 ++++++++++++++++--- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index efdbe12b859..a4cadc7d4d7 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -4,6 +4,7 @@ namespace Hyde\Framework\Testing\Unit\Support; +use Mockery; use Hyde\Facades\Filesystem; use Illuminate\Support\Facades\File; use Hyde\Framework\Exceptions\FileNotFoundException; @@ -11,6 +12,7 @@ use Hyde\Support\Filesystem\MediaFile; use Hyde\Testing\UnitTestCase; use Hyde\Testing\CreatesTemporaryFiles; +use Illuminate\Filesystem\Filesystem as BaseFilesystem; /** * @covers \Hyde\Support\Filesystem\MediaFile @@ -26,11 +28,15 @@ protected function setUp(): void { parent::setUp(); - File::shouldReceive('missing')->andReturn(false); + $this->mockFilesystem([ + 'missing' => false, + ]); } protected function tearDown(): void { + $this->withoutMockingFilesystem(); + $this->cleanUpFilesystem(); } @@ -140,21 +146,25 @@ public function testGetAbsolutePathReturnsAbsolutePathOfFile() public function testGetContentsReturnsContentsOfFile() { - $this->file('_media/foo.txt', 'foo bar'); + $this->mockFilesystem([ + 'missing' => false, + 'get' => 'foo bar', + ]); + $this->assertSame('foo bar', MediaFile::make('foo.txt')->getContents()); } public function testGetExtensionReturnsExtensionOfFile() { - $this->file('_media/foo.txt', 'foo'); $this->assertSame('txt', MediaFile::make('foo.txt')->getExtension()); - $this->file('_media/foo.png', 'foo'); $this->assertSame('png', MediaFile::make('foo.png')->getExtension()); } public function testToArrayReturnsArrayOfFileProperties() { + $this->withoutMockingFilesystem(); + $this->file('_media/foo.txt', 'foo bar'); $this->assertSame([ @@ -168,6 +178,8 @@ public function testToArrayReturnsArrayOfFileProperties() public function testToArrayWithEmptyFileWithNoExtension() { + $this->withoutMockingFilesystem(); + $this->file('_media/foo', 'foo bar'); $this->assertSame([ @@ -181,6 +193,8 @@ public function testToArrayWithEmptyFileWithNoExtension() public function testToArrayWithFileInSubdirectory() { + $this->withoutMockingFilesystem(); + mkdir(Hyde::path('_media/foo')); touch(Hyde::path('_media/foo/bar.txt')); @@ -198,7 +212,11 @@ public function testToArrayWithFileInSubdirectory() public function testGetContentLength() { - $this->file('_media/foo', 'Hello World!'); + $this->mockFilesystem([ + 'missing' => false, + 'size' => 12, + ]); + $this->assertSame(12, MediaFile::make('foo')->getContentLength()); } @@ -210,6 +228,8 @@ public function testGetContentLengthWithEmptyFile() public function testGetContentLengthWithDirectory() { + $this->withoutMockingFilesystem(); + $this->directory('_media/foo'); $this->expectException(FileNotFoundException::class); @@ -354,4 +374,14 @@ public function testGetHash() $this->assertSame(hash('crc32', 'Hello World!'), MediaFile::make('foo.txt')->getHash()); } + + protected function mockFilesystem(array $methods): void + { + app()->instance(BaseFilesystem::class, Mockery::mock(BaseFilesystem::class, $methods)); + } + + protected function withoutMockingFilesystem(): void + { + app()->forgetInstance(BaseFilesystem::class); + } } From f22f8e1854f18949b3d6a3c25a8116d18e1b9364 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:47:52 +0200 Subject: [PATCH 28/88] Revert "Refactor to use mocks" This reverts commit 070a7ff4d73797cc21b0aa858f1e5a534ffd72dd. --- .../tests/Unit/Support/MediaFileTest.php | 40 +++---------------- 1 file changed, 5 insertions(+), 35 deletions(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index a4cadc7d4d7..efdbe12b859 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -4,7 +4,6 @@ namespace Hyde\Framework\Testing\Unit\Support; -use Mockery; use Hyde\Facades\Filesystem; use Illuminate\Support\Facades\File; use Hyde\Framework\Exceptions\FileNotFoundException; @@ -12,7 +11,6 @@ use Hyde\Support\Filesystem\MediaFile; use Hyde\Testing\UnitTestCase; use Hyde\Testing\CreatesTemporaryFiles; -use Illuminate\Filesystem\Filesystem as BaseFilesystem; /** * @covers \Hyde\Support\Filesystem\MediaFile @@ -28,15 +26,11 @@ protected function setUp(): void { parent::setUp(); - $this->mockFilesystem([ - 'missing' => false, - ]); + File::shouldReceive('missing')->andReturn(false); } protected function tearDown(): void { - $this->withoutMockingFilesystem(); - $this->cleanUpFilesystem(); } @@ -146,25 +140,21 @@ public function testGetAbsolutePathReturnsAbsolutePathOfFile() public function testGetContentsReturnsContentsOfFile() { - $this->mockFilesystem([ - 'missing' => false, - 'get' => 'foo bar', - ]); - + $this->file('_media/foo.txt', 'foo bar'); $this->assertSame('foo bar', MediaFile::make('foo.txt')->getContents()); } public function testGetExtensionReturnsExtensionOfFile() { + $this->file('_media/foo.txt', 'foo'); $this->assertSame('txt', MediaFile::make('foo.txt')->getExtension()); + $this->file('_media/foo.png', 'foo'); $this->assertSame('png', MediaFile::make('foo.png')->getExtension()); } public function testToArrayReturnsArrayOfFileProperties() { - $this->withoutMockingFilesystem(); - $this->file('_media/foo.txt', 'foo bar'); $this->assertSame([ @@ -178,8 +168,6 @@ public function testToArrayReturnsArrayOfFileProperties() public function testToArrayWithEmptyFileWithNoExtension() { - $this->withoutMockingFilesystem(); - $this->file('_media/foo', 'foo bar'); $this->assertSame([ @@ -193,8 +181,6 @@ public function testToArrayWithEmptyFileWithNoExtension() public function testToArrayWithFileInSubdirectory() { - $this->withoutMockingFilesystem(); - mkdir(Hyde::path('_media/foo')); touch(Hyde::path('_media/foo/bar.txt')); @@ -212,11 +198,7 @@ public function testToArrayWithFileInSubdirectory() public function testGetContentLength() { - $this->mockFilesystem([ - 'missing' => false, - 'size' => 12, - ]); - + $this->file('_media/foo', 'Hello World!'); $this->assertSame(12, MediaFile::make('foo')->getContentLength()); } @@ -228,8 +210,6 @@ public function testGetContentLengthWithEmptyFile() public function testGetContentLengthWithDirectory() { - $this->withoutMockingFilesystem(); - $this->directory('_media/foo'); $this->expectException(FileNotFoundException::class); @@ -374,14 +354,4 @@ public function testGetHash() $this->assertSame(hash('crc32', 'Hello World!'), MediaFile::make('foo.txt')->getHash()); } - - protected function mockFilesystem(array $methods): void - { - app()->instance(BaseFilesystem::class, Mockery::mock(BaseFilesystem::class, $methods)); - } - - protected function withoutMockingFilesystem(): void - { - app()->forgetInstance(BaseFilesystem::class); - } } From 2eb56a9cd20aec28108cc931721b1c0603d1bf69 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:50:53 +0200 Subject: [PATCH 29/88] Revert "Files should receive missing and return false" This reverts commit 21340c90529c7e4335bab80c1ba9216ccab8665a. --- packages/framework/tests/Unit/Support/MediaFileTest.php | 8 -------- 1 file changed, 8 deletions(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index efdbe12b859..a0efbf73091 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -5,7 +5,6 @@ namespace Hyde\Framework\Testing\Unit\Support; use Hyde\Facades\Filesystem; -use Illuminate\Support\Facades\File; use Hyde\Framework\Exceptions\FileNotFoundException; use Hyde\Hyde; use Hyde\Support\Filesystem\MediaFile; @@ -22,13 +21,6 @@ class MediaFileTest extends UnitTestCase protected static bool $needsKernel = true; protected static bool $needsConfig = true; - protected function setUp(): void - { - parent::setUp(); - - File::shouldReceive('missing')->andReturn(false); - } - protected function tearDown(): void { $this->cleanUpFilesystem(); From 000f19a1e9fb5ed5e8ed6f8ca6642eb23264ef9c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:54:39 +0200 Subject: [PATCH 30/88] Create public internal static property to control validation --- packages/framework/src/Support/Filesystem/MediaFile.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 445748f9f46..94495885257 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -29,12 +29,15 @@ class MediaFile extends ProjectFile /** @var array The default extensions for media types */ final public const EXTENSIONS = ['png', 'svg', 'jpg', 'jpeg', 'gif', 'ico', 'css', 'js']; + /** @internal Controls whether to validate the existence of the file. Turning this off may lead to unexpected behavior. */ + public static bool $validateExistence = true; + public function __construct(string $path) { $path = trim_slashes(Str::after(Hyde::pathToRelative($path), Hyde::getMediaDirectory())); $path = static::sourcePath($path); - if (Filesystem::missing($path)) { + if (static::$validateExistence && Filesystem::missing($path)) { throw new FileNotFoundException($path); } From 21df2e36039e5596a078c17412d8aeb951fbc524 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:55:30 +0200 Subject: [PATCH 31/88] Disable existence validation during unit tests --- .../tests/Unit/Foundation/FilesystemHasMediaFilesTest.php | 7 +++++++ packages/framework/tests/Unit/Support/MediaFileTest.php | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php b/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php index 594e6966bcf..f55345c8487 100644 --- a/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php +++ b/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php @@ -24,6 +24,13 @@ protected function setUp(): void { parent::setUp(); $this->filesystem = new TestableFilesystem(Hyde::getInstance()); + MediaFile::$validateExistence = false; + } + + protected function tearDown(): void + { + parent::tearDown(); + MediaFile::$validateExistence = true; } public function testAssetsMethodReturnsSameInstanceOnSubsequentCalls() diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index a0efbf73091..c9efd3452b4 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -21,9 +21,16 @@ class MediaFileTest extends UnitTestCase protected static bool $needsKernel = true; protected static bool $needsConfig = true; + protected function setUp(): void + { + MediaFile::$validateExistence = false; + } + protected function tearDown(): void { $this->cleanUpFilesystem(); + + MediaFile::$validateExistence = true; } /** @deprecated */ From bfda13398798420d1ef22a21c8f357f103c91a63 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 14:31:35 +0200 Subject: [PATCH 32/88] Normalize paths using output directory to have source directory prefix --- .../src/Support/Filesystem/MediaFile.php | 9 ++++++++- .../tests/Unit/Support/MediaFileTest.php | 18 ++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 94495885257..1cf472168cd 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -34,7 +34,14 @@ class MediaFile extends ProjectFile public function __construct(string $path) { - $path = trim_slashes(Str::after(Hyde::pathToRelative($path), Hyde::getMediaDirectory())); + $path = Hyde::pathToRelative($path); + + // Normalize paths using output directory to have source directory prefix + if (str_starts_with($path, Hyde::getMediaOutputDirectory()) && str_starts_with(Hyde::getMediaDirectory(), '_')) { + $path = '_'.$path; + } + + $path = trim_slashes(Str::after($path, Hyde::getMediaDirectory())); $path = static::sourcePath($path); if (static::$validateExistence && Filesystem::missing($path)) { diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index c9efd3452b4..aa39a7a51a9 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -108,6 +108,16 @@ public function testAbsoluteMediaPathIsNormalizedToRelativeMediaPath() $this->assertSame('_media/foo', MediaFile::make(Hyde::path('_media/foo'))->path); } + public function testOutputMediaPathIsNormalizedToRelativeMediaPath() + { + $this->assertSame('_media/foo', MediaFile::make('media/foo')->path); + } + + public function testAbsoluteOutputMediaPathIsNormalizedToRelativeMediaPath() + { + $this->assertSame('_media/foo', MediaFile::make(Hyde::path('media/foo'))->path); + } + public function testCustomMediaPathsAreNormalizedToRelativeCustomizedMediaPath() { Hyde::setMediaDirectory('bar'); @@ -116,6 +126,14 @@ public function testCustomMediaPathsAreNormalizedToRelativeCustomizedMediaPath() $this->assertSame('bar/foo', MediaFile::make('bar/foo')->path); $this->assertSame('bar/foo', MediaFile::make(Hyde::path('foo'))->path); + Hyde::setMediaDirectory('_bar'); + + $this->assertSame('_bar/foo', MediaFile::make('foo')->path); + $this->assertSame('_bar/foo', MediaFile::make('_bar/foo')->path); + $this->assertSame('_bar/foo', MediaFile::make(Hyde::path('_bar/foo'))->path); + $this->assertSame('_bar/foo', MediaFile::make('bar/foo')->path); + $this->assertSame('_bar/foo', MediaFile::make(Hyde::path('foo'))->path); + Hyde::setMediaDirectory('_media'); } From 13266594d8cd401e4e6d2ec1e8a314014fb4b7a0 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 13:56:48 +0200 Subject: [PATCH 33/88] Test existence validation --- .../tests/Unit/Support/MediaFileTest.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index aa39a7a51a9..d774c47e0f4 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -371,4 +371,23 @@ public function testGetHash() $this->assertSame(hash('crc32', 'Hello World!'), MediaFile::make('foo.txt')->getHash()); } + + public function testExceptionIsThrownWhenConstructingFileThatDoesNotExist() + { + MediaFile::$validateExistence = true; + + $this->expectException(FileNotFoundException::class); + $this->expectExceptionMessage('File [_media/foo] not found.'); + + MediaFile::make('foo'); + } + + public function testExceptionIsNotThrownWhenConstructingFileThatDoesExist() + { + MediaFile::$validateExistence = true; + + $this->file('_media/foo', 'Hello World!'); + + $this->assertInstanceOf(MediaFile::class, MediaFile::make('foo')); + } } From 0ccec37131d1d87a468a70616707c1986c1e6797 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 14:42:44 +0200 Subject: [PATCH 34/88] Remove content length validation now performed at construct time --- .../src/Support/Filesystem/MediaFile.php | 5 ----- .../tests/Unit/Support/MediaFileTest.php | 18 ------------------ 2 files changed, 23 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 1cf472168cd..3d3ff974168 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -19,7 +19,6 @@ use function array_merge; use function filesize; use function pathinfo; -use function is_file; /** * File abstraction for a project media file. @@ -106,10 +105,6 @@ public function toArray(): array public function getContentLength(): int { - if (! is_file($this->getAbsolutePath())) { - throw new FileNotFoundException($this->path); - } - return filesize($this->getAbsolutePath()); } diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index d774c47e0f4..6d82881a2d0 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -225,24 +225,6 @@ public function testGetContentLengthWithEmptyFile() $this->assertSame(0, MediaFile::make('foo')->getContentLength()); } - public function testGetContentLengthWithDirectory() - { - $this->directory('_media/foo'); - - $this->expectException(FileNotFoundException::class); - $this->expectExceptionMessage('File [_media/foo] not found.'); - - MediaFile::make('foo')->getContentLength(); - } - - public function testGetContentLengthWithNonExistentFile() - { - $this->expectException(FileNotFoundException::class); - $this->expectExceptionMessage('File [_media/foo] not found.'); - - MediaFile::make('foo')->getContentLength(); - } - public function testGetMimeType() { $this->file('_media/foo.txt', 'Hello World!'); From 9a7f58b16eb32e13fb123c6895ddb641c375ad0b Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 14:51:45 +0200 Subject: [PATCH 35/88] Extract method to normalize path --- .../src/Support/Filesystem/MediaFile.php | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 3d3ff974168..e543da54f1a 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -33,15 +33,7 @@ class MediaFile extends ProjectFile public function __construct(string $path) { - $path = Hyde::pathToRelative($path); - - // Normalize paths using output directory to have source directory prefix - if (str_starts_with($path, Hyde::getMediaOutputDirectory()) && str_starts_with(Hyde::getMediaDirectory(), '_')) { - $path = '_'.$path; - } - - $path = trim_slashes(Str::after($path, Hyde::getMediaDirectory())); - $path = static::sourcePath($path); + $path = $this->normalizePath($path); if (static::$validateExistence && Filesystem::missing($path)) { throw new FileNotFoundException($path); @@ -152,4 +144,16 @@ public static function getCacheBustKey(string $file): string ? '?v='.static::make($file)->getHash() : ''; } + + protected function normalizePath(string $path): string + { + $path = Hyde::pathToRelative($path); + + // Normalize paths using output directory to have source directory prefix + if (str_starts_with($path, Hyde::getMediaOutputDirectory()) && str_starts_with(Hyde::getMediaDirectory(), '_')) { + $path = '_'.$path; + } + + return static::sourcePath(trim_slashes(Str::after($path, Hyde::getMediaDirectory()))); + } } From 5f037217327f2d813f88502cca2d484829e9991e Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 14:57:20 +0200 Subject: [PATCH 36/88] Set metadata properties at construct time --- .../framework/src/Support/Filesystem/MediaFile.php | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index e543da54f1a..b33a4d6b66e 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -31,6 +31,10 @@ class MediaFile extends ProjectFile /** @internal Controls whether to validate the existence of the file. Turning this off may lead to unexpected behavior. */ public static bool $validateExistence = true; + protected int $length; + protected string $mimeType; + protected string $hash; + public function __construct(string $path) { $path = $this->normalizePath($path); @@ -40,6 +44,12 @@ public function __construct(string $path) } parent::__construct($path); + + if (is_file($this->getAbsolutePath())) { + $this->length = filesize($this->getAbsolutePath()); + $this->mimeType = $this->getMimeType(); + $this->hash = $this->getHash(); + } } /** @return \Illuminate\Support\Collection The array keys are the filenames relative to the _media/ directory */ From 937917f4dca94bf39e6a823f86c44a2cee916f48 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 15:15:34 +0200 Subject: [PATCH 37/88] Return value when set --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index b33a4d6b66e..2c88ffc74a9 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -107,6 +107,10 @@ public function toArray(): array public function getContentLength(): int { + if (isset($this->length)) { + return $this->length; + } + return filesize($this->getAbsolutePath()); } From cb37c4e05b335c72d178eb2c756ff80469ccb407 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 15:15:50 +0200 Subject: [PATCH 38/88] Return value when set --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 2c88ffc74a9..0dd583ba96a 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -116,6 +116,10 @@ public function getContentLength(): int public function getMimeType(): string { + if (isset($this->mimeType)) { + return $this->mimeType; + } + $extension = pathinfo($this->getAbsolutePath(), PATHINFO_EXTENSION); // See if we can find a mime type for the extension instead of From 523051fa8b026445e37afba6f78eac725425700c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 15:16:04 +0200 Subject: [PATCH 39/88] Return value when set --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 0dd583ba96a..15071dabf63 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -152,6 +152,10 @@ public function getMimeType(): string public function getHash(): string { + if (isset($this->hash)) { + return $this->hash; + } + return hash_file('crc32', $this->getAbsolutePath()); } From e3104fb087cafa6bdff8f55560da25770abbbc59 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 16:03:57 +0200 Subject: [PATCH 40/88] Assume value is set --- packages/framework/src/Support/Filesystem/MediaFile.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 15071dabf63..e5da6935844 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -107,11 +107,7 @@ public function toArray(): array public function getContentLength(): int { - if (isset($this->length)) { - return $this->length; - } - - return filesize($this->getAbsolutePath()); + return $this->length; } public function getMimeType(): string From 134d24e8a923af356b671d42d4551fad9138061f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 17:23:40 +0200 Subject: [PATCH 41/88] Revert "Assume value is set" This reverts commit e3104fb087cafa6bdff8f55560da25770abbbc59. --- packages/framework/src/Support/Filesystem/MediaFile.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index e5da6935844..15071dabf63 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -107,7 +107,11 @@ public function toArray(): array public function getContentLength(): int { - return $this->length; + if (isset($this->length)) { + return $this->length; + } + + return filesize($this->getAbsolutePath()); } public function getMimeType(): string From 8b9de19736624406c8c2848d52835356918316e4 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 17:34:48 +0200 Subject: [PATCH 42/88] Find all media file metadata at construct time --- .../src/Support/Filesystem/MediaFile.php | 73 ++++++++++--------- .../tests/Unit/Support/MediaFileTest.php | 2 + 2 files changed, 40 insertions(+), 35 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 15071dabf63..8efd9e2f169 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -46,9 +46,9 @@ public function __construct(string $path) parent::__construct($path); if (is_file($this->getAbsolutePath())) { - $this->length = filesize($this->getAbsolutePath()); - $this->mimeType = $this->getMimeType(); - $this->hash = $this->getHash(); + $this->length = $this->findContentLength(); + $this->mimeType = $this->findMimeType(); + $this->hash = $this->findHash(); } } @@ -107,19 +107,46 @@ public function toArray(): array public function getContentLength(): int { - if (isset($this->length)) { - return $this->length; - } - - return filesize($this->getAbsolutePath()); + return $this->length; } public function getMimeType(): string { - if (isset($this->mimeType)) { - return $this->mimeType; + return $this->mimeType; + } + + public function getHash(): string + { + return $this->hash; + } + + /** @internal */ + public static function getCacheBustKey(string $file): string + { + return Config::getBool('hyde.enable_cache_busting', true) && file_exists(static::sourcePath("$file")) + ? '?v='.static::make($file)->getHash() + : ''; + } + + protected function normalizePath(string $path): string + { + $path = Hyde::pathToRelative($path); + + // Normalize paths using output directory to have source directory prefix + if (str_starts_with($path, Hyde::getMediaOutputDirectory()) && str_starts_with(Hyde::getMediaDirectory(), '_')) { + $path = '_'.$path; } + return static::sourcePath(trim_slashes(Str::after($path, Hyde::getMediaDirectory()))); + } + + protected function findContentLength(): int + { + return filesize($this->getAbsolutePath()); + } + + protected function findMimeType(): string + { $extension = pathinfo($this->getAbsolutePath(), PATHINFO_EXTENSION); // See if we can find a mime type for the extension instead of @@ -150,32 +177,8 @@ public function getMimeType(): string return 'text/plain'; } - public function getHash(): string + protected function findHash(): string { - if (isset($this->hash)) { - return $this->hash; - } - return hash_file('crc32', $this->getAbsolutePath()); } - - /** @internal */ - public static function getCacheBustKey(string $file): string - { - return Config::getBool('hyde.enable_cache_busting', true) && file_exists(static::sourcePath("$file")) - ? '?v='.static::make($file)->getHash() - : ''; - } - - protected function normalizePath(string $path): string - { - $path = Hyde::pathToRelative($path); - - // Normalize paths using output directory to have source directory prefix - if (str_starts_with($path, Hyde::getMediaOutputDirectory()) && str_starts_with(Hyde::getMediaDirectory(), '_')) { - $path = '_'.$path; - } - - return static::sourcePath(trim_slashes(Str::after($path, Hyde::getMediaDirectory()))); - } } diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index 6d82881a2d0..04369d9d514 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -245,12 +245,14 @@ public function testGetMimeTypeWithEmptyFile() public function testGetMimeTypeWithDirectory() { + $this->markTestSkipped('Undecided on what should happen here.'); $this->directory('_media/foo'); $this->assertSame('directory', MediaFile::make('foo')->getMimeType()); } public function testGetMimeTypeWithNonExistentFile() { + $this->markTestSkipped('Undecided on what should happen here.'); $this->assertSame('text/plain', MediaFile::make('foo')->getMimeType()); } From d4a9390f967f63c478a14c40f6a2709b2e05b702 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 17:37:58 +0200 Subject: [PATCH 43/88] Remove tests for weird edge cases with no benefit --- .../framework/tests/Unit/Support/MediaFileTest.php | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileTest.php b/packages/framework/tests/Unit/Support/MediaFileTest.php index 04369d9d514..6b2a1d10fc8 100644 --- a/packages/framework/tests/Unit/Support/MediaFileTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileTest.php @@ -243,19 +243,6 @@ public function testGetMimeTypeWithEmptyFile() $this->assertSame('application/x-empty', MediaFile::make('foo')->getMimeType()); } - public function testGetMimeTypeWithDirectory() - { - $this->markTestSkipped('Undecided on what should happen here.'); - $this->directory('_media/foo'); - $this->assertSame('directory', MediaFile::make('foo')->getMimeType()); - } - - public function testGetMimeTypeWithNonExistentFile() - { - $this->markTestSkipped('Undecided on what should happen here.'); - $this->assertSame('text/plain', MediaFile::make('foo')->getMimeType()); - } - public function testAllHelperReturnsAllMediaFiles() { $this->assertEquals([ From 39d5169da36e26ae608b4c67199240cc518268f2 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:10:04 +0200 Subject: [PATCH 44/88] Split out unit test and feature test --- .../tests/Feature/Support/MediaFileTest.php | 23 +++++++++++++++++++ ...ediaFileTest.php => MediaFileUnitTest.php} | 4 +++- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 packages/framework/tests/Feature/Support/MediaFileTest.php rename packages/framework/tests/Unit/Support/{MediaFileTest.php => MediaFileUnitTest.php} (99%) diff --git a/packages/framework/tests/Feature/Support/MediaFileTest.php b/packages/framework/tests/Feature/Support/MediaFileTest.php new file mode 100644 index 00000000000..f1c6a0a74dd --- /dev/null +++ b/packages/framework/tests/Feature/Support/MediaFileTest.php @@ -0,0 +1,23 @@ + Date: Mon, 29 Jul 2024 20:12:39 +0200 Subject: [PATCH 45/88] Generate feature test with Claude --- .../tests/Feature/Support/MediaFileTest.php | 96 ++++++++++++++++++- 1 file changed, 95 insertions(+), 1 deletion(-) diff --git a/packages/framework/tests/Feature/Support/MediaFileTest.php b/packages/framework/tests/Feature/Support/MediaFileTest.php index f1c6a0a74dd..d336b54fe2a 100644 --- a/packages/framework/tests/Feature/Support/MediaFileTest.php +++ b/packages/framework/tests/Feature/Support/MediaFileTest.php @@ -19,5 +19,99 @@ */ class MediaFileTest extends TestCase { - // + public function testMediaFileCreationAndBasicProperties() + { + $this->file('_media/test.txt', 'Hello, World!'); + + $mediaFile = MediaFile::make('test.txt'); + + $this->assertInstanceOf(MediaFile::class, $mediaFile); + $this->assertEquals('test.txt', $mediaFile->getName()); + $this->assertEquals('_media/test.txt', $mediaFile->getPath()); + $this->assertEquals(Hyde::path('_media/test.txt'), $mediaFile->getAbsolutePath()); + $this->assertEquals('Hello, World!', $mediaFile->getContents()); + $this->assertEquals('txt', $mediaFile->getExtension()); + } + + public function testMediaFileDiscovery() + { + $this->file('_media/image.png', 'PNG content'); + $this->file('_media/style.css', 'CSS content'); + $this->file('_media/script.js', 'JS content'); + + $allFiles = MediaFile::all(); + + $this->assertCount(3, $allFiles); + $this->assertArrayHasKey('image.png', $allFiles); + $this->assertArrayHasKey('style.css', $allFiles); + $this->assertArrayHasKey('script.js', $allFiles); + + $fileNames = MediaFile::files(); + $this->assertEquals(['image.png', 'style.css', 'script.js'], $fileNames); + } + + public function testMediaFileProperties() + { + $content = str_repeat('a', 1024); // 1KB content + $this->file('_media/large_file.txt', $content); + + $mediaFile = MediaFile::make('large_file.txt'); + + $this->assertEquals(1024, $mediaFile->getContentLength()); + $this->assertEquals('text/plain', $mediaFile->getMimeType()); + $this->assertEquals(hash('crc32', $content), $mediaFile->getHash()); + } + + public function testMediaFilePathHandling() + { + $this->file('_media/subfolder/nested_file.txt', 'Nested content'); + + $mediaFile = MediaFile::make('subfolder/nested_file.txt'); + + $this->assertEquals('subfolder/nested_file.txt', $mediaFile->getIdentifier()); + $this->assertEquals('_media/subfolder/nested_file.txt', $mediaFile->getPath()); + } + + public function testMediaFileExceptionHandling() + { + MediaFile::$validateExistence = true; + + $this->expectException(FileNotFoundException::class); + MediaFile::make('non_existent_file.txt'); + } + + public function testMediaDirectoryCustomization() + { + Hyde::setMediaDirectory('custom_media'); + + $this->file('custom_media/custom_file.txt', 'Custom content'); + + $mediaFile = MediaFile::make('custom_file.txt'); + + $this->assertEquals('custom_media/custom_file.txt', $mediaFile->getPath()); + $this->assertEquals(Hyde::path('custom_media/custom_file.txt'), $mediaFile->getAbsolutePath()); + + Hyde::setMediaDirectory('_media'); // Reset to default + } + + public function testMediaFileOutputPaths() + { + $this->assertEquals(Hyde::path('_site/media'), MediaFile::outputPath()); + $this->assertEquals(Hyde::path('_site/media/test.css'), MediaFile::outputPath('test.css')); + + Hyde::setOutputDirectory('custom_output'); + $this->assertEquals(Hyde::path('custom_output/media'), MediaFile::outputPath()); + + Hyde::setOutputDirectory('_site'); // Reset to default + } + + public function testMediaFileCacheBusting() + { + $this->file('_media/cachebust_test.js', 'console.log("Hello");'); + + $cacheBustKey = MediaFile::getCacheBustKey('cachebust_test.js'); + + $this->assertStringStartsWith('?v=', $cacheBustKey); + $this->assertNotEquals('?v=', $cacheBustKey); // Ensure it's not empty + } } From 84591e4c517d3ebc9a626ece56765238dba26958 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:12:49 +0200 Subject: [PATCH 46/88] Fix all 'Unused import' problems in file --- packages/framework/tests/Feature/Support/MediaFileTest.php | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/framework/tests/Feature/Support/MediaFileTest.php b/packages/framework/tests/Feature/Support/MediaFileTest.php index d336b54fe2a..06caf8059e3 100644 --- a/packages/framework/tests/Feature/Support/MediaFileTest.php +++ b/packages/framework/tests/Feature/Support/MediaFileTest.php @@ -6,10 +6,7 @@ use Hyde\Hyde; use Hyde\Testing\TestCase; -use Hyde\Facades\Filesystem; -use Hyde\Testing\UnitTestCase; use Hyde\Support\Filesystem\MediaFile; -use Hyde\Testing\CreatesTemporaryFiles; use Hyde\Framework\Exceptions\FileNotFoundException; /** From ec8099b8b5ec2c48403f6ff3d91a1bf0ad9850d5 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:13:34 +0200 Subject: [PATCH 47/88] Expect default file --- packages/framework/tests/Feature/Support/MediaFileTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/framework/tests/Feature/Support/MediaFileTest.php b/packages/framework/tests/Feature/Support/MediaFileTest.php index 06caf8059e3..8d05f889096 100644 --- a/packages/framework/tests/Feature/Support/MediaFileTest.php +++ b/packages/framework/tests/Feature/Support/MediaFileTest.php @@ -32,19 +32,20 @@ public function testMediaFileCreationAndBasicProperties() public function testMediaFileDiscovery() { + // App.css is a default file $this->file('_media/image.png', 'PNG content'); $this->file('_media/style.css', 'CSS content'); $this->file('_media/script.js', 'JS content'); $allFiles = MediaFile::all(); - $this->assertCount(3, $allFiles); + $this->assertCount(4, $allFiles); $this->assertArrayHasKey('image.png', $allFiles); $this->assertArrayHasKey('style.css', $allFiles); $this->assertArrayHasKey('script.js', $allFiles); $fileNames = MediaFile::files(); - $this->assertEquals(['image.png', 'style.css', 'script.js'], $fileNames); + $this->assertEquals(['image.png', 'app.css', 'style.css', 'script.js'], $fileNames); } public function testMediaFileProperties() From d819bff24fcfb74159cd19135eef65b8923bd819 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:14:05 +0200 Subject: [PATCH 48/88] Remove setter for already default value --- packages/framework/tests/Feature/Support/MediaFileTest.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/framework/tests/Feature/Support/MediaFileTest.php b/packages/framework/tests/Feature/Support/MediaFileTest.php index 8d05f889096..db9f789f012 100644 --- a/packages/framework/tests/Feature/Support/MediaFileTest.php +++ b/packages/framework/tests/Feature/Support/MediaFileTest.php @@ -72,8 +72,6 @@ public function testMediaFilePathHandling() public function testMediaFileExceptionHandling() { - MediaFile::$validateExistence = true; - $this->expectException(FileNotFoundException::class); MediaFile::make('non_existent_file.txt'); } From c51915e921a02ff75c0e8644bef6960666fcef29 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:14:52 +0200 Subject: [PATCH 49/88] Expect CRC32 hash --- packages/framework/tests/Feature/Support/MediaFileTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/tests/Feature/Support/MediaFileTest.php b/packages/framework/tests/Feature/Support/MediaFileTest.php index db9f789f012..f68cc16dab1 100644 --- a/packages/framework/tests/Feature/Support/MediaFileTest.php +++ b/packages/framework/tests/Feature/Support/MediaFileTest.php @@ -108,6 +108,6 @@ public function testMediaFileCacheBusting() $cacheBustKey = MediaFile::getCacheBustKey('cachebust_test.js'); $this->assertStringStartsWith('?v=', $cacheBustKey); - $this->assertNotEquals('?v=', $cacheBustKey); // Ensure it's not empty + $this->assertSame('?v=cd5de5e7', $cacheBustKey); // Expect crc32 hash } } From 36f3545ba04895971c1df3ee9f277c3a8bf77ac9 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:16:04 +0200 Subject: [PATCH 50/88] Cleanup test code comments --- packages/framework/tests/Feature/Support/MediaFileTest.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/framework/tests/Feature/Support/MediaFileTest.php b/packages/framework/tests/Feature/Support/MediaFileTest.php index f68cc16dab1..8daf91809ab 100644 --- a/packages/framework/tests/Feature/Support/MediaFileTest.php +++ b/packages/framework/tests/Feature/Support/MediaFileTest.php @@ -87,7 +87,7 @@ public function testMediaDirectoryCustomization() $this->assertEquals('custom_media/custom_file.txt', $mediaFile->getPath()); $this->assertEquals(Hyde::path('custom_media/custom_file.txt'), $mediaFile->getAbsolutePath()); - Hyde::setMediaDirectory('_media'); // Reset to default + Hyde::setMediaDirectory('_media'); } public function testMediaFileOutputPaths() @@ -98,7 +98,7 @@ public function testMediaFileOutputPaths() Hyde::setOutputDirectory('custom_output'); $this->assertEquals(Hyde::path('custom_output/media'), MediaFile::outputPath()); - Hyde::setOutputDirectory('_site'); // Reset to default + Hyde::setOutputDirectory('_site'); } public function testMediaFileCacheBusting() @@ -108,6 +108,6 @@ public function testMediaFileCacheBusting() $cacheBustKey = MediaFile::getCacheBustKey('cachebust_test.js'); $this->assertStringStartsWith('?v=', $cacheBustKey); - $this->assertSame('?v=cd5de5e7', $cacheBustKey); // Expect crc32 hash + $this->assertSame('?v=cd5de5e7', $cacheBustKey); // Expect CRC32 hash } } From 3a1c66bbd6a07ae1c4b923007713d4a947d79fc3 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:16:08 +0200 Subject: [PATCH 51/88] Use assert same instead of assert equals --- .../tests/Feature/Support/MediaFileTest.php | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/framework/tests/Feature/Support/MediaFileTest.php b/packages/framework/tests/Feature/Support/MediaFileTest.php index 8daf91809ab..a82e6f71456 100644 --- a/packages/framework/tests/Feature/Support/MediaFileTest.php +++ b/packages/framework/tests/Feature/Support/MediaFileTest.php @@ -23,11 +23,11 @@ public function testMediaFileCreationAndBasicProperties() $mediaFile = MediaFile::make('test.txt'); $this->assertInstanceOf(MediaFile::class, $mediaFile); - $this->assertEquals('test.txt', $mediaFile->getName()); - $this->assertEquals('_media/test.txt', $mediaFile->getPath()); - $this->assertEquals(Hyde::path('_media/test.txt'), $mediaFile->getAbsolutePath()); - $this->assertEquals('Hello, World!', $mediaFile->getContents()); - $this->assertEquals('txt', $mediaFile->getExtension()); + $this->assertSame('test.txt', $mediaFile->getName()); + $this->assertSame('_media/test.txt', $mediaFile->getPath()); + $this->assertSame(Hyde::path('_media/test.txt'), $mediaFile->getAbsolutePath()); + $this->assertSame('Hello, World!', $mediaFile->getContents()); + $this->assertSame('txt', $mediaFile->getExtension()); } public function testMediaFileDiscovery() @@ -45,7 +45,7 @@ public function testMediaFileDiscovery() $this->assertArrayHasKey('script.js', $allFiles); $fileNames = MediaFile::files(); - $this->assertEquals(['image.png', 'app.css', 'style.css', 'script.js'], $fileNames); + $this->assertSame(['image.png', 'app.css', 'style.css', 'script.js'], $fileNames); } public function testMediaFileProperties() @@ -55,9 +55,9 @@ public function testMediaFileProperties() $mediaFile = MediaFile::make('large_file.txt'); - $this->assertEquals(1024, $mediaFile->getContentLength()); - $this->assertEquals('text/plain', $mediaFile->getMimeType()); - $this->assertEquals(hash('crc32', $content), $mediaFile->getHash()); + $this->assertSame(1024, $mediaFile->getContentLength()); + $this->assertSame('text/plain', $mediaFile->getMimeType()); + $this->assertSame(hash('crc32', $content), $mediaFile->getHash()); } public function testMediaFilePathHandling() @@ -66,8 +66,8 @@ public function testMediaFilePathHandling() $mediaFile = MediaFile::make('subfolder/nested_file.txt'); - $this->assertEquals('subfolder/nested_file.txt', $mediaFile->getIdentifier()); - $this->assertEquals('_media/subfolder/nested_file.txt', $mediaFile->getPath()); + $this->assertSame('subfolder/nested_file.txt', $mediaFile->getIdentifier()); + $this->assertSame('_media/subfolder/nested_file.txt', $mediaFile->getPath()); } public function testMediaFileExceptionHandling() @@ -84,19 +84,19 @@ public function testMediaDirectoryCustomization() $mediaFile = MediaFile::make('custom_file.txt'); - $this->assertEquals('custom_media/custom_file.txt', $mediaFile->getPath()); - $this->assertEquals(Hyde::path('custom_media/custom_file.txt'), $mediaFile->getAbsolutePath()); + $this->assertSame('custom_media/custom_file.txt', $mediaFile->getPath()); + $this->assertSame(Hyde::path('custom_media/custom_file.txt'), $mediaFile->getAbsolutePath()); Hyde::setMediaDirectory('_media'); } public function testMediaFileOutputPaths() { - $this->assertEquals(Hyde::path('_site/media'), MediaFile::outputPath()); - $this->assertEquals(Hyde::path('_site/media/test.css'), MediaFile::outputPath('test.css')); + $this->assertSame(Hyde::path('_site/media'), MediaFile::outputPath()); + $this->assertSame(Hyde::path('_site/media/test.css'), MediaFile::outputPath('test.css')); Hyde::setOutputDirectory('custom_output'); - $this->assertEquals(Hyde::path('custom_output/media'), MediaFile::outputPath()); + $this->assertSame(Hyde::path('custom_output/media'), MediaFile::outputPath()); Hyde::setOutputDirectory('_site'); } From 521df1ea6cca43274443c48cf4268d4f1a4c3337 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:17:33 +0200 Subject: [PATCH 52/88] Assert on the array --- .../framework/tests/Feature/Support/MediaFileTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/framework/tests/Feature/Support/MediaFileTest.php b/packages/framework/tests/Feature/Support/MediaFileTest.php index a82e6f71456..df8756e6551 100644 --- a/packages/framework/tests/Feature/Support/MediaFileTest.php +++ b/packages/framework/tests/Feature/Support/MediaFileTest.php @@ -28,6 +28,14 @@ public function testMediaFileCreationAndBasicProperties() $this->assertSame(Hyde::path('_media/test.txt'), $mediaFile->getAbsolutePath()); $this->assertSame('Hello, World!', $mediaFile->getContents()); $this->assertSame('txt', $mediaFile->getExtension()); + + $this->assertSame([ + 'name' => 'test.txt', + 'path' => '_media/test.txt', + 'length' => 13, + 'mimeType' => 'text/plain', + 'hash' => 'dffed8e6', + ], $mediaFile->toArray()); } public function testMediaFileDiscovery() From 77722257a228f911861f778a5dd062f98f64f461 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:39:56 +0200 Subject: [PATCH 53/88] Bypass discovery to isolate unit test --- .../tests/Unit/IncludesFacadeUnitTest.php | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php index 6dac17db2f5..74818e459e8 100644 --- a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php +++ b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php @@ -9,12 +9,17 @@ use Hyde\Hyde; use Hyde\Support\Includes; use Hyde\Testing\UnitTestCase; +use Hyde\Foundation\HydeKernel; use Hyde\Support\Facades\Render; use Illuminate\Support\HtmlString; +use Illuminate\Support\Collection; use Hyde\Support\Models\RenderData; use Illuminate\Support\Facades\Blade; use Illuminate\Filesystem\Filesystem; use Hyde\Testing\MocksKernelFeatures; +use Hyde\Foundation\Kernel\FileCollection; +use Hyde\Foundation\Kernel\PageCollection; +use Hyde\Foundation\Kernel\RouteCollection; /** * @covers \Hyde\Support\Includes @@ -37,6 +42,22 @@ protected function setUp(): void $this->setupTestKernel(); $this->kernel->setRoutes(collect()); Render::swap(new RenderData()); + + HydeKernel::setInstance(new class extends HydeKernel + { + // Bypass discovery to isolate test + public function boot(): void + { + $this->files = FileCollection::init($this); + $this->pages = PageCollection::init($this); + $this->routes = RouteCollection::init($this); + } + + public function assets(): Collection + { + return collect(); + } + }); } protected function tearDown(): void From 1f28f2123133f1499b2f783e2eff0a1de343494c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:25:48 +0200 Subject: [PATCH 54/88] Refactor media file class to use the Filesystem facade This makes unit testing easier as it's mockable --- .../src/Support/Filesystem/MediaFile.php | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 8efd9e2f169..aa703d81bdc 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -15,10 +15,7 @@ use function Hyde\path_join; use function Hyde\trim_slashes; use function extension_loaded; -use function file_exists; use function array_merge; -use function filesize; -use function pathinfo; /** * File abstraction for a project media file. @@ -45,7 +42,7 @@ public function __construct(string $path) parent::__construct($path); - if (is_file($this->getAbsolutePath())) { + if (Filesystem::isFile($this->getAbsolutePath())) { $this->length = $this->findContentLength(); $this->mimeType = $this->findMimeType(); $this->hash = $this->findHash(); @@ -123,7 +120,7 @@ public function getHash(): string /** @internal */ public static function getCacheBustKey(string $file): string { - return Config::getBool('hyde.enable_cache_busting', true) && file_exists(static::sourcePath("$file")) + return Config::getBool('hyde.enable_cache_busting', true) && Filesystem::exists(static::sourcePath("$file")) ? '?v='.static::make($file)->getHash() : ''; } @@ -142,12 +139,12 @@ protected function normalizePath(string $path): string protected function findContentLength(): int { - return filesize($this->getAbsolutePath()); + return Filesystem::size($this->getAbsolutePath()); } protected function findMimeType(): string { - $extension = pathinfo($this->getAbsolutePath(), PATHINFO_EXTENSION); + $extension = Filesystem::extension($this->getAbsolutePath()); // See if we can find a mime type for the extension instead of // having to rely on a PHP extension and filesystem lookups. @@ -170,8 +167,8 @@ protected function findMimeType(): string return $lookup[$extension]; } - if (extension_loaded('fileinfo') && file_exists($this->getAbsolutePath())) { - return mime_content_type($this->getAbsolutePath()); + if (extension_loaded('fileinfo') && Filesystem::exists($this->getAbsolutePath())) { + return Filesystem::mimeType($this->getAbsolutePath()); } return 'text/plain'; @@ -179,6 +176,6 @@ protected function findMimeType(): string protected function findHash(): string { - return hash_file('crc32', $this->getAbsolutePath()); + return Filesystem::hash($this->getAbsolutePath(), 'crc32'); } } From bc4c511b5d0657a2fbd4bbea608518d756bfae0f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:27:02 +0200 Subject: [PATCH 55/88] No need to qualify path handled by Filesystem facade --- .../framework/src/Support/Filesystem/MediaFile.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index aa703d81bdc..24e45f3a5c8 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -42,7 +42,7 @@ public function __construct(string $path) parent::__construct($path); - if (Filesystem::isFile($this->getAbsolutePath())) { + if (Filesystem::isFile($this->getPath())) { $this->length = $this->findContentLength(); $this->mimeType = $this->findMimeType(); $this->hash = $this->findHash(); @@ -139,12 +139,12 @@ protected function normalizePath(string $path): string protected function findContentLength(): int { - return Filesystem::size($this->getAbsolutePath()); + return Filesystem::size($this->getPath()); } protected function findMimeType(): string { - $extension = Filesystem::extension($this->getAbsolutePath()); + $extension = Filesystem::extension($this->getPath()); // See if we can find a mime type for the extension instead of // having to rely on a PHP extension and filesystem lookups. @@ -167,8 +167,8 @@ protected function findMimeType(): string return $lookup[$extension]; } - if (extension_loaded('fileinfo') && Filesystem::exists($this->getAbsolutePath())) { - return Filesystem::mimeType($this->getAbsolutePath()); + if (extension_loaded('fileinfo') && Filesystem::exists($this->getPath())) { + return Filesystem::mimeType($this->getPath()); } return 'text/plain'; @@ -176,6 +176,6 @@ protected function findMimeType(): string protected function findHash(): string { - return Filesystem::hash($this->getAbsolutePath(), 'crc32'); + return Filesystem::hash($this->getPath(), 'crc32'); } } From 5e3e279c80413a46cd0b20ea157a192d74dafdfb Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 20:49:01 +0200 Subject: [PATCH 56/88] Prepare unit test for refactor --- .../tests/Unit/Support/MediaFileUnitTest.php | 50 +++++-------------- 1 file changed, 13 insertions(+), 37 deletions(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php index af0fa5546bd..1d63abcb810 100644 --- a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php @@ -4,12 +4,14 @@ namespace Hyde\Framework\Testing\Unit\Support; +use Mockery; use Hyde\Facades\Filesystem; use Hyde\Framework\Exceptions\FileNotFoundException; use Hyde\Hyde; use Hyde\Support\Filesystem\MediaFile; use Hyde\Testing\UnitTestCase; use Hyde\Testing\CreatesTemporaryFiles; +use Illuminate\Filesystem\Filesystem as BaseFilesystem; /** * @covers \Hyde\Support\Filesystem\MediaFile @@ -18,6 +20,7 @@ */ class MediaFileUnitTest extends UnitTestCase { + // TODO: Use mocks here instead of filesystem operations use CreatesTemporaryFiles; protected static bool $needsKernel = true; @@ -26,52 +29,20 @@ class MediaFileUnitTest extends UnitTestCase protected function setUp(): void { MediaFile::$validateExistence = false; + + $this->mockFilesystem([ + 'missing' => false, + ]); } protected function tearDown(): void { + // TODO: Use mocks here instead of filesystem operations $this->cleanUpFilesystem(); MediaFile::$validateExistence = true; } - /** @deprecated */ - public function testDiscoveryBenchmark() - { - $this->markTestSkipped('Uncomment this line to run the benchmark.'); - - $urls = [ - 'https://raw.githubusercontent.com/caendesilva/RandomDatasets/master/Media/austria.jpg', - 'https://raw.githubusercontent.com/caendesilva/RandomDatasets/master/Media/boat.jpg', - 'https://raw.githubusercontent.com/caendesilva/RandomDatasets/master/Media/croatia.jpg', - 'https://raw.githubusercontent.com/caendesilva/RandomDatasets/master/Media/fireworks.jpg', - 'https://raw.githubusercontent.com/caendesilva/RandomDatasets/master/Media/hallstatt.jpg', - 'https://raw.githubusercontent.com/caendesilva/RandomDatasets/master/Media/lemonade.jpg', - 'https://raw.githubusercontent.com/caendesilva/RandomDatasets/master/Media/photographer.jpg', - ]; - - foreach ($urls as $url) { - $this->file('_media/'.basename($url), file_get_contents($url)); - } - - $this->file('_media/foo.css', 'body { color: red; }'); - $this->file('_media/foo.js', 'console.log("Hello, World!");'); - $this->file('_media/nested/foo.css', 'foo'); - $this->file('_media/empty.css', ''); - $this->file('_media/ignored', 'ignored'); - $this->directory('_media/empty'); - $this->file('_media/large.css', str_repeat('a', 1024 * 1024 * 10)); // 10 MB - - // Warm up the classloader / cache - echo 'Warmup: '.\Illuminate\Support\Benchmark::measure(function () { - MediaFile::all(); - })."ms\n"; - - echo 'Benchmark: '.\Illuminate\Support\Benchmark::measure(function () { - MediaFile::all(); - }, 1000)."ms avg/1000/its\n"; - } - public function testCanConstruct() { $file = new MediaFile('foo'); @@ -363,4 +334,9 @@ public function testExceptionIsNotThrownWhenConstructingFileThatDoesExist() $this->assertInstanceOf(MediaFile::class, MediaFile::make('foo')); } + + protected function mockFilesystem(array $methods): void + { + app()->instance(BaseFilesystem::class, Mockery::mock(BaseFilesystem::class, $methods)); + } } From 749e3ead3827e4ff2d7330a80fde407507979631 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 22:42:15 +0200 Subject: [PATCH 57/88] Refactor unit test to use the filesystem mocks --- .../tests/Unit/Support/MediaFileUnitTest.php | 217 +++++------------- 1 file changed, 63 insertions(+), 154 deletions(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php index 1d63abcb810..cebc5c29fe4 100644 --- a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php @@ -5,12 +5,10 @@ namespace Hyde\Framework\Testing\Unit\Support; use Mockery; -use Hyde\Facades\Filesystem; use Hyde\Framework\Exceptions\FileNotFoundException; use Hyde\Hyde; use Hyde\Support\Filesystem\MediaFile; use Hyde\Testing\UnitTestCase; -use Hyde\Testing\CreatesTemporaryFiles; use Illuminate\Filesystem\Filesystem as BaseFilesystem; /** @@ -20,27 +18,40 @@ */ class MediaFileUnitTest extends UnitTestCase { - // TODO: Use mocks here instead of filesystem operations - use CreatesTemporaryFiles; - protected static bool $needsKernel = true; protected static bool $needsConfig = true; + protected $mockFilesystem; + protected function setUp(): void { + parent::setUp(); + MediaFile::$validateExistence = false; - $this->mockFilesystem([ - 'missing' => false, - ]); + $this->mockFilesystem = Mockery::mock(BaseFilesystem::class); + app()->instance(BaseFilesystem::class, $this->mockFilesystem); + + // Set up default expectations for commonly called methods + $this->mockFilesystem->shouldReceive('isFile')->andReturn(true)->byDefault(); + $this->mockFilesystem->shouldReceive('missing')->andReturn(false)->byDefault(); + $this->mockFilesystem->shouldReceive('extension')->andReturn('txt')->byDefault(); + $this->mockFilesystem->shouldReceive('size')->andReturn(12)->byDefault(); + $this->mockFilesystem->shouldReceive('mimeType')->andReturn('text/plain')->byDefault(); + $this->mockFilesystem->shouldReceive('hash')->andReturn(hash('crc32', 'Hello World!'))->byDefault(); + $this->mockFilesystem->shouldReceive('get')->andReturn('Hello World!')->byDefault(); + + // Mock Hyde facade + $hyde = Mockery::mock(Hyde::kernel())->makePartial(); + $hyde->shouldReceive('assets')->andReturn(collect(['app.css' => new MediaFile('_media/app.css')]))->byDefault(); } protected function tearDown(): void { - // TODO: Use mocks here instead of filesystem operations - $this->cleanUpFilesystem(); + parent::tearDown(); MediaFile::$validateExistence = true; + Mockery::close(); } public function testCanConstruct() @@ -130,22 +141,40 @@ public function testGetAbsolutePathReturnsAbsolutePathOfFile() public function testGetContentsReturnsContentsOfFile() { - $this->file('_media/foo.txt', 'foo bar'); + $this->mockFilesystem->shouldReceive('get') + ->with(Hyde::path('_media/foo.txt')) + ->andReturn('foo bar'); + $this->assertSame('foo bar', MediaFile::make('foo.txt')->getContents()); } public function testGetExtensionReturnsExtensionOfFile() { - $this->file('_media/foo.txt', 'foo'); - $this->assertSame('txt', MediaFile::make('foo.txt')->getExtension()); + $this->mockFilesystem->shouldReceive('extension') + ->with(Hyde::path('_media/foo.txt')) + ->andReturn('txt'); + + $this->mockFilesystem->shouldReceive('extension') + ->with(Hyde::path('_media/foo.png')) + ->andReturn('png'); - $this->file('_media/foo.png', 'foo'); + $this->assertSame('txt', MediaFile::make('foo.txt')->getExtension()); $this->assertSame('png', MediaFile::make('foo.png')->getExtension()); } public function testToArrayReturnsArrayOfFileProperties() { - $this->file('_media/foo.txt', 'foo bar'); + $this->mockFilesystem->shouldReceive('size') + ->with(Hyde::path('_media/foo.txt')) + ->andReturn(7); + + $this->mockFilesystem->shouldReceive('mimeType') + ->with(Hyde::path('_media/foo.txt')) + ->andReturn('text/plain'); + + $this->mockFilesystem->shouldReceive('hash') + ->with(Hyde::path('_media/foo.txt'), 'crc32') + ->andReturn(hash('crc32', 'foo bar')); $this->assertSame([ 'name' => 'foo.txt', @@ -156,64 +185,22 @@ public function testToArrayReturnsArrayOfFileProperties() ], MediaFile::make('foo.txt')->toArray()); } - public function testToArrayWithEmptyFileWithNoExtension() - { - $this->file('_media/foo', 'foo bar'); - - $this->assertSame([ - 'name' => 'foo', - 'path' => '_media/foo', - 'length' => 7, - 'mimeType' => 'text/plain', - 'hash' => hash('crc32', 'foo bar'), - ], MediaFile::make('foo')->toArray()); - } - - public function testToArrayWithFileInSubdirectory() - { - mkdir(Hyde::path('_media/foo')); - touch(Hyde::path('_media/foo/bar.txt')); - - $this->assertSame([ - 'name' => 'bar.txt', - 'path' => '_media/foo/bar.txt', - 'length' => 0, - 'mimeType' => 'text/plain', - 'hash' => hash('crc32', ''), - ], MediaFile::make('foo/bar.txt')->toArray()); - - Filesystem::unlink('_media/foo/bar.txt'); - rmdir(Hyde::path('_media/foo')); - } - public function testGetContentLength() { - $this->file('_media/foo', 'Hello World!'); - $this->assertSame(12, MediaFile::make('foo')->getContentLength()); - } + $this->mockFilesystem->shouldReceive('size') + ->with(Hyde::path('_media/foo')) + ->andReturn(12); - public function testGetContentLengthWithEmptyFile() - { - $this->file('_media/foo', ''); - $this->assertSame(0, MediaFile::make('foo')->getContentLength()); + $this->assertSame(12, MediaFile::make('foo')->getContentLength()); } public function testGetMimeType() { - $this->file('_media/foo.txt', 'Hello World!'); - $this->assertSame('text/plain', MediaFile::make('foo.txt')->getMimeType()); - } - - public function testGetMimeTypeWithoutExtension() - { - $this->file('_media/foo', 'Hello World!'); - $this->assertSame('text/plain', MediaFile::make('foo')->getMimeType()); - } + $this->mockFilesystem->shouldReceive('mimeType') + ->with(Hyde::path('_media/foo.txt')) + ->andReturn('text/plain'); - public function testGetMimeTypeWithEmptyFile() - { - $this->file('_media/foo', ''); - $this->assertSame('application/x-empty', MediaFile::make('foo')->getMimeType()); + $this->assertSame('text/plain', MediaFile::make('foo.txt')->getMimeType()); } public function testAllHelperReturnsAllMediaFiles() @@ -223,95 +210,16 @@ public function testAllHelperReturnsAllMediaFiles() ], MediaFile::all()->all()); } - public function testAllHelperDoesNotIncludeNonMediaFiles() - { - $this->file('_media/foo.blade.php'); - - $this->assertEquals([ - 'app.css' => new MediaFile('_media/app.css'), - ], MediaFile::all()->all()); - } - public function testFilesHelperReturnsAllMediaFiles() { $this->assertSame(['app.css'], MediaFile::files()); } - public function testGetIdentifierReturnsIdentifier() + public function testGetHashReturnsHash() { - $this->assertSame('foo', MediaFile::make('foo')->getIdentifier()); - } - - public function testGetIdentifierWithSubdirectory() - { - $this->assertSame('foo/bar', MediaFile::make('foo/bar')->getIdentifier()); - } - - public function testGetIdentifierReturnsIdentifierWithFileExtension() - { - $this->assertSame('foo.png', MediaFile::make('foo.png')->getIdentifier()); - } - - public function testGetIdentifierWithSubdirectoryWithFileExtension() - { - $this->assertSame('foo/bar.png', MediaFile::make('foo/bar.png')->getIdentifier()); - } - - public function testHelperForMediaPath() - { - $this->assertSame(Hyde::path('_media'), MediaFile::sourcePath()); - } - - public function testHelperForMediaPathReturnsPathToFileWithinTheDirectory() - { - $this->assertSame(Hyde::path('_media/foo.css'), MediaFile::sourcePath('foo.css')); - } - - public function testGetMediaPathReturnsAbsolutePath() - { - $this->assertSame(Hyde::path('_media'), MediaFile::sourcePath()); - } - - public function testHelperForMediaOutputPath() - { - $this->assertSame(Hyde::path('_site/media'), MediaFile::outputPath()); - } - - public function testHelperForMediaOutputPathReturnsPathToFileWithinTheDirectory() - { - $this->assertSame(Hyde::path('_site/media/foo.css'), MediaFile::outputPath('foo.css')); - } - - public function testGetMediaOutputPathReturnsAbsolutePath() - { - $this->assertSame(Hyde::path('_site/media'), MediaFile::outputPath()); - } - - public function testCanGetSiteMediaOutputDirectory() - { - $this->assertSame(Hyde::path('_site/media'), MediaFile::outputPath()); - } - - public function testGetSiteMediaOutputDirectoryUsesTrimmedVersionOfMediaSourceDirectory() - { - Hyde::setMediaDirectory('_foo'); - $this->assertSame(Hyde::path('_site/foo'), MediaFile::outputPath()); - } - - public function testGetSiteMediaOutputDirectoryUsesConfiguredSiteOutputDirectory() - { - Hyde::setOutputDirectory(Hyde::path('foo')); - Hyde::setMediaDirectory('bar'); - - $this->assertSame(Hyde::path('foo/bar'), MediaFile::outputPath()); - - Hyde::setOutputDirectory(Hyde::path('_site')); - Hyde::setMediaDirectory('_media'); - } - - public function testGetHash() - { - $this->file('_media/foo.txt', 'Hello World!'); + $this->mockFilesystem->shouldReceive('hash') + ->with(Hyde::path('_media/foo.txt'), 'crc32') + ->andReturn(hash('crc32', 'Hello World!')); $this->assertSame(hash('crc32', 'Hello World!'), MediaFile::make('foo.txt')->getHash()); } @@ -320,6 +228,10 @@ public function testExceptionIsThrownWhenConstructingFileThatDoesNotExist() { MediaFile::$validateExistence = true; + $this->mockFilesystem->shouldReceive('missing') + ->with(Hyde::path('_media/foo')) + ->andReturn(true); + $this->expectException(FileNotFoundException::class); $this->expectExceptionMessage('File [_media/foo] not found.'); @@ -330,13 +242,10 @@ public function testExceptionIsNotThrownWhenConstructingFileThatDoesExist() { MediaFile::$validateExistence = true; - $this->file('_media/foo', 'Hello World!'); + $this->mockFilesystem->shouldReceive('missing') + ->with(Hyde::path('_media/foo')) + ->andReturn(false); $this->assertInstanceOf(MediaFile::class, MediaFile::make('foo')); } - - protected function mockFilesystem(array $methods): void - { - app()->instance(BaseFilesystem::class, Mockery::mock(BaseFilesystem::class, $methods)); - } } From cbdf54069bfc9cb20c7a038cf980285e979ed9c1 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Mon, 29 Jul 2024 22:43:11 +0200 Subject: [PATCH 58/88] Fix failing unit test --- packages/framework/tests/Unit/Support/MediaFileUnitTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php index cebc5c29fe4..32652ad4537 100644 --- a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php @@ -142,8 +142,8 @@ public function testGetAbsolutePathReturnsAbsolutePathOfFile() public function testGetContentsReturnsContentsOfFile() { $this->mockFilesystem->shouldReceive('get') - ->with(Hyde::path('_media/foo.txt')) - ->andReturn('foo bar'); + ->andReturn('foo bar') + ->once(); $this->assertSame('foo bar', MediaFile::make('foo.txt')->getContents()); } From 77574224204021374a11c88d49554fdba51ba5a3 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Tue, 30 Jul 2024 12:39:00 +0200 Subject: [PATCH 59/88] Reset kernel --- packages/framework/tests/Unit/IncludesFacadeUnitTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php index 74818e459e8..3a39dc18873 100644 --- a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php +++ b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php @@ -63,6 +63,7 @@ public function assets(): Collection protected function tearDown(): void { Mockery::close(); + self::resetKernel(); parent::tearDown(); } From 160e401dfe3c5d6ffd92733badf48fdb044b45ed Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Tue, 30 Jul 2024 12:58:21 +0200 Subject: [PATCH 60/88] Run test without app stylesheet --- .../tests/Unit/IncludesFacadeUnitTest.php | 35 ++++++++----------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php index 3a39dc18873..ae21891d6e0 100644 --- a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php +++ b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php @@ -9,17 +9,12 @@ use Hyde\Hyde; use Hyde\Support\Includes; use Hyde\Testing\UnitTestCase; -use Hyde\Foundation\HydeKernel; use Hyde\Support\Facades\Render; use Illuminate\Support\HtmlString; -use Illuminate\Support\Collection; use Hyde\Support\Models\RenderData; use Illuminate\Support\Facades\Blade; use Illuminate\Filesystem\Filesystem; use Hyde\Testing\MocksKernelFeatures; -use Hyde\Foundation\Kernel\FileCollection; -use Hyde\Foundation\Kernel\PageCollection; -use Hyde\Foundation\Kernel\RouteCollection; /** * @covers \Hyde\Support\Includes @@ -42,22 +37,6 @@ protected function setUp(): void $this->setupTestKernel(); $this->kernel->setRoutes(collect()); Render::swap(new RenderData()); - - HydeKernel::setInstance(new class extends HydeKernel - { - // Bypass discovery to isolate test - public function boot(): void - { - $this->files = FileCollection::init($this); - $this->pages = PageCollection::init($this); - $this->routes = RouteCollection::init($this); - } - - public function assets(): Collection - { - return collect(); - } - }); } protected function tearDown(): void @@ -68,6 +47,20 @@ protected function tearDown(): void parent::tearDown(); } + public static function setUpBeforeClass(): void + { + rename('_media/app.css', '_media/app.css.bak'); + + parent::setUpBeforeClass(); + } + + public static function tearDownAfterClass(): void + { + rename('_media/app.css.bak', '_media/app.css'); + + parent::tearDownAfterClass(); + } + public function testPathReturnsTheIncludesDirectory() { $this->assertSame(Hyde::path('resources/includes'), Includes::path()); From c585ee330ccc0e0ff9d34a3c464ac5a77e3c484c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Tue, 30 Jul 2024 20:20:36 +0200 Subject: [PATCH 61/88] Revert "Reset kernel" This reverts commit 26aa0b1d3559c597a9e15f7483cb5ba50c075ad7. --- packages/framework/tests/Unit/IncludesFacadeUnitTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php index ae21891d6e0..4abd3b12054 100644 --- a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php +++ b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php @@ -42,7 +42,6 @@ protected function setUp(): void protected function tearDown(): void { Mockery::close(); - self::resetKernel(); parent::tearDown(); } From afc9b012c0362e36e37973126d5764cdcaa10b21 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Tue, 30 Jul 2024 20:20:39 +0200 Subject: [PATCH 62/88] Revert "Run test without app stylesheet" This reverts commit 28024ed16bb68d21e77f83a270648e20a665dafa. --- .../tests/Unit/IncludesFacadeUnitTest.php | 35 +++++++++++-------- 1 file changed, 21 insertions(+), 14 deletions(-) diff --git a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php index 4abd3b12054..74818e459e8 100644 --- a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php +++ b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php @@ -9,12 +9,17 @@ use Hyde\Hyde; use Hyde\Support\Includes; use Hyde\Testing\UnitTestCase; +use Hyde\Foundation\HydeKernel; use Hyde\Support\Facades\Render; use Illuminate\Support\HtmlString; +use Illuminate\Support\Collection; use Hyde\Support\Models\RenderData; use Illuminate\Support\Facades\Blade; use Illuminate\Filesystem\Filesystem; use Hyde\Testing\MocksKernelFeatures; +use Hyde\Foundation\Kernel\FileCollection; +use Hyde\Foundation\Kernel\PageCollection; +use Hyde\Foundation\Kernel\RouteCollection; /** * @covers \Hyde\Support\Includes @@ -37,6 +42,22 @@ protected function setUp(): void $this->setupTestKernel(); $this->kernel->setRoutes(collect()); Render::swap(new RenderData()); + + HydeKernel::setInstance(new class extends HydeKernel + { + // Bypass discovery to isolate test + public function boot(): void + { + $this->files = FileCollection::init($this); + $this->pages = PageCollection::init($this); + $this->routes = RouteCollection::init($this); + } + + public function assets(): Collection + { + return collect(); + } + }); } protected function tearDown(): void @@ -46,20 +67,6 @@ protected function tearDown(): void parent::tearDown(); } - public static function setUpBeforeClass(): void - { - rename('_media/app.css', '_media/app.css.bak'); - - parent::setUpBeforeClass(); - } - - public static function tearDownAfterClass(): void - { - rename('_media/app.css.bak', '_media/app.css'); - - parent::tearDownAfterClass(); - } - public function testPathReturnsTheIncludesDirectory() { $this->assertSame(Hyde::path('resources/includes'), Includes::path()); From 025b35e084d85192283b9a4c1e91583e536140ea Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Tue, 30 Jul 2024 12:32:37 +0200 Subject: [PATCH 63/88] Update MediaFileUnitTest.php --- .../tests/Unit/Support/MediaFileUnitTest.php | 98 ++++++++++++++++--- 1 file changed, 86 insertions(+), 12 deletions(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php index 32652ad4537..b7093bddd45 100644 --- a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php @@ -21,8 +21,26 @@ class MediaFileUnitTest extends UnitTestCase protected static bool $needsKernel = true; protected static bool $needsConfig = true; + protected static string $originalBasePath; + protected $mockFilesystem; + public static function setUpBeforeClass(): void + { + parent::setUpBeforeClass(); + + static::$originalBasePath = Hyde::getBasePath(); + + Hyde::setBasePath('/base/path'); + } + + public static function tearDownAfterClass(): void + { + Hyde::setBasePath(static::$originalBasePath); + + parent::tearDownAfterClass(); + } + protected function setUp(): void { parent::setUp(); @@ -203,18 +221,6 @@ public function testGetMimeType() $this->assertSame('text/plain', MediaFile::make('foo.txt')->getMimeType()); } - public function testAllHelperReturnsAllMediaFiles() - { - $this->assertEquals([ - 'app.css' => new MediaFile('_media/app.css'), - ], MediaFile::all()->all()); - } - - public function testFilesHelperReturnsAllMediaFiles() - { - $this->assertSame(['app.css'], MediaFile::files()); - } - public function testGetHashReturnsHash() { $this->mockFilesystem->shouldReceive('hash') @@ -248,4 +254,72 @@ public function testExceptionIsNotThrownWhenConstructingFileThatDoesExist() $this->assertInstanceOf(MediaFile::class, MediaFile::make('foo')); } + + public function testGetIdentifierWithSubdirectory() + { + $this->assertSame('foo/bar', MediaFile::make('foo/bar')->getIdentifier()); + } + + public function testGetIdentifierReturnsIdentifierWithFileExtension() + { + $this->assertSame('foo.png', MediaFile::make('foo.png')->getIdentifier()); + } + + public function testGetIdentifierWithSubdirectoryWithFileExtension() + { + $this->assertSame('foo/bar.png', MediaFile::make('foo/bar.png')->getIdentifier()); + } + + public function testHelperForMediaPath() + { + $this->assertSame('/base/path/_media', MediaFile::sourcePath()); + } + + public function testHelperForMediaPathReturnsPathToFileWithinTheDirectory() + { + $this->assertSame('/base/path/_media/foo.css', MediaFile::sourcePath('foo.css')); + } + + public function testGetMediaPathReturnsAbsolutePath() + { + $this->assertSame('/base/path/_media', MediaFile::sourcePath()); + } + + public function testHelperForMediaOutputPath() + { + $this->assertSame('/base/path/_site/media', MediaFile::outputPath()); + } + + public function testHelperForMediaOutputPathReturnsPathToFileWithinTheDirectory() + { + $this->assertSame('/base/path/_site/media/foo.css', MediaFile::outputPath('foo.css')); + } + + public function testGetMediaOutputPathReturnsAbsolutePath() + { + $this->assertSame('/base/path/_site/media', MediaFile::outputPath()); + } + + public function testCanGetSiteMediaOutputDirectory() + { + $this->assertSame('/base/path/_site/media', MediaFile::outputPath()); + } + + public function testGetSiteMediaOutputDirectoryUsesTrimmedVersionOfMediaSourceDirectory() + { + Hyde::setMediaDirectory('_foo'); + $this->assertSame('/base/path/_site/foo', MediaFile::outputPath()); + Hyde::setMediaDirectory('_media'); // Reset to default + } + + public function testGetSiteMediaOutputDirectoryUsesConfiguredSiteOutputDirectory() + { + Hyde::setOutputDirectory('/base/path/foo'); + Hyde::setMediaDirectory('bar'); + + $this->assertSame('/base/path/foo/bar', MediaFile::outputPath()); + + Hyde::setOutputDirectory('/base/path/_site'); // Reset to default + Hyde::setMediaDirectory('_media'); // Reset to default + } } From 9d288782f0dc51345b3b96e641359f11ddded615 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Tue, 30 Jul 2024 20:33:19 +0200 Subject: [PATCH 64/88] Swap for a simpler implementation --- .../tests/Unit/IncludesFacadeUnitTest.php | 35 ++++++++----------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php index 74818e459e8..bcf6d47cebe 100644 --- a/packages/framework/tests/Unit/IncludesFacadeUnitTest.php +++ b/packages/framework/tests/Unit/IncludesFacadeUnitTest.php @@ -8,18 +8,15 @@ use Closure; use Hyde\Hyde; use Hyde\Support\Includes; +use Illuminate\Support\Str; use Hyde\Testing\UnitTestCase; -use Hyde\Foundation\HydeKernel; use Hyde\Support\Facades\Render; use Illuminate\Support\HtmlString; -use Illuminate\Support\Collection; use Hyde\Support\Models\RenderData; use Illuminate\Support\Facades\Blade; use Illuminate\Filesystem\Filesystem; use Hyde\Testing\MocksKernelFeatures; -use Hyde\Foundation\Kernel\FileCollection; -use Hyde\Foundation\Kernel\PageCollection; -use Hyde\Foundation\Kernel\RouteCollection; +use Hyde\Framework\Services\MarkdownService; /** * @covers \Hyde\Support\Includes @@ -43,21 +40,7 @@ protected function setUp(): void $this->kernel->setRoutes(collect()); Render::swap(new RenderData()); - HydeKernel::setInstance(new class extends HydeKernel - { - // Bypass discovery to isolate test - public function boot(): void - { - $this->files = FileCollection::init($this); - $this->pages = PageCollection::init($this); - $this->routes = RouteCollection::init($this); - } - - public function assets(): Collection - { - return collect(); - } - }); + app()->bind(MarkdownService::class, SimpleMarkdownServiceTestClass::class); } protected function tearDown(): void @@ -276,3 +259,15 @@ protected function assertHtmlStringIsSame(string|HtmlString $expected, mixed $ac $this->assertSame((string) $expected, $actual->toHtml()); } } + +class SimpleMarkdownServiceTestClass +{ + public function __construct(protected string $markdown = '') + { + } + + public function parse(): string + { + return Str::markdown($this->markdown); + } +} From 3089fbcb41af5f4ff64d246cfa0f67fba62a074f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 12:01:16 +0200 Subject: [PATCH 65/88] Use fully qualified class name in PHPDoc --- .../partials/hyde-pages-api/hyde-kernel-filesystem-methods.md | 4 ++-- .../framework/src/Foundation/Concerns/ForwardsFilesystem.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md b/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md index 9823b18f5f4..fa76f9881e7 100644 --- a/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md +++ b/docs/_data/partials/hyde-pages-api/hyde-kernel-filesystem-methods.md @@ -1,7 +1,7 @@
- + #### `filesystem()` @@ -56,7 +56,7 @@ Hyde::pathToRelative(string $path): string No description provided. ```php -Hyde::assets(): Collection +Hyde::assets(): \Illuminate\Support\Collection ``` diff --git a/packages/framework/src/Foundation/Concerns/ForwardsFilesystem.php b/packages/framework/src/Foundation/Concerns/ForwardsFilesystem.php index 1f45bc30655..b294170474f 100644 --- a/packages/framework/src/Foundation/Concerns/ForwardsFilesystem.php +++ b/packages/framework/src/Foundation/Concerns/ForwardsFilesystem.php @@ -44,7 +44,7 @@ public function pathToRelative(string $path): string return $this->filesystem->pathToRelative($path); } - /** @return Collection */ + /** @return \Illuminate\Support\Collection */ public function assets(): Collection { return $this->filesystem->assets(); From e1a39098a1bff028586125525d3ee73bf6dabffe Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 12:13:37 +0200 Subject: [PATCH 66/88] Clarify existence of internal property --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 24e45f3a5c8..3e584380b97 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -25,7 +25,7 @@ class MediaFile extends ProjectFile /** @var array The default extensions for media types */ final public const EXTENSIONS = ['png', 'svg', 'jpg', 'jpeg', 'gif', 'ico', 'css', 'js']; - /** @internal Controls whether to validate the existence of the file. Turning this off may lead to unexpected behavior. */ + /** @internal Controls whether to validate the existence of the file, intended for unit testing. Turning this off may lead to unexpected behavior. */ public static bool $validateExistence = true; protected int $length; From cc87ff93e62cfed79a545b695b5885c4de5e3a7f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 12:25:06 +0200 Subject: [PATCH 67/88] Mock base filesystem --- .../tests/Unit/Foundation/FilesystemHasMediaFilesTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php b/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php index f55345c8487..e23e7ad8177 100644 --- a/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php +++ b/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php @@ -4,11 +4,13 @@ namespace Hyde\Framework\Testing\Unit\Foundation; +use Mockery; use Hyde\Foundation\Kernel\Filesystem; use Hyde\Hyde; use Hyde\Support\Filesystem\MediaFile; use Hyde\Testing\UnitTestCase; use Illuminate\Support\Collection; +use Illuminate\Filesystem\Filesystem as BaseFilesystem; /** * @covers \Hyde\Foundation\Kernel\Filesystem @@ -24,6 +26,12 @@ protected function setUp(): void { parent::setUp(); $this->filesystem = new TestableFilesystem(Hyde::getInstance()); + + $mock = Mockery::mock(BaseFilesystem::class)->makePartial(); + $mock->shouldReceive('size')->andReturn(100)->byDefault(); + $mock->shouldReceive('hash')->andReturn('hash')->byDefault(); + app()->instance(BaseFilesystem::class, $mock); + MediaFile::$validateExistence = false; } From bec2d608e2a3bf1dee22ab75ef44a2540ff3a8c2 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 12:14:29 +0200 Subject: [PATCH 68/88] Remove file existence check before getting data --- packages/framework/src/Support/Filesystem/MediaFile.php | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 3e584380b97..e39d2c1c8f8 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -42,11 +42,9 @@ public function __construct(string $path) parent::__construct($path); - if (Filesystem::isFile($this->getPath())) { - $this->length = $this->findContentLength(); - $this->mimeType = $this->findMimeType(); - $this->hash = $this->findHash(); - } + $this->length = $this->findContentLength(); + $this->mimeType = $this->findMimeType(); + $this->hash = $this->findHash(); } /** @return \Illuminate\Support\Collection The array keys are the filenames relative to the _media/ directory */ From 818f939bec04b2608d62fd6ad1bbb00d5c1526aa Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 13:01:38 +0200 Subject: [PATCH 69/88] Match method declaration order to the base page class --- .../framework/src/Support/Filesystem/MediaFile.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index e39d2c1c8f8..8d8cb16c279 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -47,18 +47,18 @@ public function __construct(string $path) $this->hash = $this->findHash(); } - /** @return \Illuminate\Support\Collection The array keys are the filenames relative to the _media/ directory */ - public static function all(): Collection - { - return Hyde::assets(); - } - /** @return array Array of filenames relative to the _media/ directory */ public static function files(): array { return static::all()->keys()->all(); } + /** @return \Illuminate\Support\Collection The array keys are the filenames relative to the _media/ directory */ + public static function all(): Collection + { + return Hyde::assets(); + } + /** * Get the absolute path to the media source directory, or a file within it. */ From 2471dfaa82b710ea5fccd45e6eb82556b4b6103a Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 13:04:37 +0200 Subject: [PATCH 70/88] Add an example return value --- packages/framework/src/Support/Filesystem/MediaFile.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 8d8cb16c279..5266da067c1 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -47,7 +47,11 @@ public function __construct(string $path) $this->hash = $this->findHash(); } - /** @return array Array of filenames relative to the _media/ directory */ + /** + * @return array Array of filenames relative to the _media/ directory + * + * @example `['app.css', 'images/logo.svg']` + */ public static function files(): array { return static::all()->keys()->all(); From 1b85baa8b7462d576b5b56d3414e8facd4cf910c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 13:10:53 +0200 Subject: [PATCH 71/88] Merge example to single line --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 5266da067c1..8f4a0cf807a 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -48,9 +48,7 @@ public function __construct(string $path) } /** - * @return array Array of filenames relative to the _media/ directory - * - * @example `['app.css', 'images/logo.svg']` + * @return array Array of filenames relative to the _media/ directory {@example `['app.css', 'images/logo.svg']`} */ public static function files(): array { From 8c20420636f37a1df1933aa69e79b1af751929b6 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 13:10:56 +0200 Subject: [PATCH 72/88] Revert "Merge example to single line" This reverts commit 1b85baa8b7462d576b5b56d3414e8facd4cf910c. --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 8f4a0cf807a..5266da067c1 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -48,7 +48,9 @@ public function __construct(string $path) } /** - * @return array Array of filenames relative to the _media/ directory {@example `['app.css', 'images/logo.svg']`} + * @return array Array of filenames relative to the _media/ directory + * + * @example `['app.css', 'images/logo.svg']` */ public static function files(): array { From 814b3eb22f8c5878a3e1c6a10df177d4ca3ee863 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 13:11:36 +0200 Subject: [PATCH 73/88] Add return prefix --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 5266da067c1..a913f75c9cf 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -50,7 +50,7 @@ public function __construct(string $path) /** * @return array Array of filenames relative to the _media/ directory * - * @example `['app.css', 'images/logo.svg']` + * @example `$return = ['app.css', 'images/logo.svg']` */ public static function files(): array { From 2802ae2bf366ae5a9a5a19a05c49ad6a45086a78 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 13:11:39 +0200 Subject: [PATCH 74/88] Revert "Add return prefix" This reverts commit 814b3eb22f8c5878a3e1c6a10df177d4ca3ee863. --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index a913f75c9cf..5266da067c1 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -50,7 +50,7 @@ public function __construct(string $path) /** * @return array Array of filenames relative to the _media/ directory * - * @example `$return = ['app.css', 'images/logo.svg']` + * @example `['app.css', 'images/logo.svg']` */ public static function files(): array { From 3441c5339b025bf87c6f0553e9af22ae10dbcd4f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 13:13:56 +0200 Subject: [PATCH 75/88] Improve the method documentation --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 5266da067c1..5cb87350239 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -48,9 +48,9 @@ public function __construct(string $path) } /** - * @return array Array of filenames relative to the _media/ directory + * Get an array of media asset filenames relative to the `_media/` directory. * - * @example `['app.css', 'images/logo.svg']` + * @return array {@example `['app.css', 'images/logo.svg']`} */ public static function files(): array { From 067a8058d8778654a1df24827427bce1ca6cb867 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 13:16:26 +0200 Subject: [PATCH 76/88] Improve the method documentation --- packages/framework/src/Support/Filesystem/MediaFile.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 5cb87350239..3ae480b230c 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -57,7 +57,11 @@ public static function files(): array return static::all()->keys()->all(); } - /** @return \Illuminate\Support\Collection The array keys are the filenames relative to the _media/ directory */ + /** + * Get a collection of all media files, parsed into MediaFile instances, keyed by the filenames relative to the `_media/` directory. + * + * @return \Illuminate\Support\Collection + */ public static function all(): Collection { return Hyde::assets(); From 31d8d2ae25f4a23f774a4de66f49df5504235a5c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 13:17:06 +0200 Subject: [PATCH 77/88] Format documented class name --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 3ae480b230c..e5a2d910455 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -58,7 +58,7 @@ public static function files(): array } /** - * Get a collection of all media files, parsed into MediaFile instances, keyed by the filenames relative to the `_media/` directory. + * Get a collection of all media files, parsed into `MediaFile` instances, keyed by the filenames relative to the `_media/` directory. * * @return \Illuminate\Support\Collection */ From c4dc0f7e9a414843f4085e617046118f1681beae Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 13:37:52 +0200 Subject: [PATCH 78/88] Generate more unit tests to cover all code paths --- .../tests/Unit/Support/MediaFileUnitTest.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php index b7093bddd45..1af72abfcc2 100644 --- a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php @@ -322,4 +322,34 @@ public function testGetSiteMediaOutputDirectoryUsesConfiguredSiteOutputDirectory Hyde::setOutputDirectory('/base/path/_site'); // Reset to default Hyde::setMediaDirectory('_media'); // Reset to default } + + public function testSourcePathWithEmptyString() + { + $this->assertSame(Hyde::path('_media'), MediaFile::sourcePath('')); + } + + public function testSourcePathWithSubdirectories() + { + $this->assertSame(Hyde::path('_media/foo/bar'), MediaFile::sourcePath('foo/bar')); + } + + public function testSourcePathWithLeadingSlash() + { + $this->assertSame(Hyde::path('_media/foo'), MediaFile::sourcePath('/foo')); + } + + public function testOutputPathWithEmptyString() + { + $this->assertSame(Hyde::sitePath('media'), MediaFile::outputPath('')); + } + + public function testOutputPathWithSubdirectories() + { + $this->assertSame(Hyde::sitePath('media/foo/bar'), MediaFile::outputPath('foo/bar')); + } + + public function testOutputPathWithLeadingSlash() + { + $this->assertSame(Hyde::sitePath('media/foo'), MediaFile::outputPath('/foo')); + } } From e31458451c1a460ee55bff68712ad2f4e6bbbbd8 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 15:11:46 +0200 Subject: [PATCH 79/88] Generate more constructor unit tests --- .../tests/Unit/Support/MediaFileUnitTest.php | 53 +++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php index 1af72abfcc2..1585bfb6acd 100644 --- a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php @@ -139,6 +139,59 @@ public function testCustomMediaPathsAreNormalizedToRelativeCustomizedMediaPath() Hyde::setMediaDirectory('_media'); } + public function testConstructorWithVariousInputFormats() + { + $this->assertSame('_media/foo.txt', MediaFile::make('foo.txt')->path); + $this->assertSame('_media/foo.txt', MediaFile::make('_media/foo.txt')->path); + $this->assertSame('_media/foo.txt', MediaFile::make(Hyde::path('_media/foo.txt'))->path); + $this->assertSame('_media/foo.txt', MediaFile::make('media/foo.txt')->path); + } + + public function testConstructorWithValidationDisabled() + { + MediaFile::$validateExistence = false; + $this->mockFilesystem->shouldReceive('missing')->never(); + + $file = new MediaFile('non_existent_file.txt'); + $this->assertInstanceOf(MediaFile::class, $file); + } + + public function testConstructorSetsProperties() + { + $file = new MediaFile('foo.txt'); + $this->assertNotNull($file->length); + $this->assertNotNull($file->mimeType); + $this->assertNotNull($file->hash); + } + + public function testNormalizePathWithAbsolutePath() + { + $this->assertSame('_media/foo.txt', MediaFile::make(Hyde::path('_media/foo.txt'))->path); + } + + public function testNormalizePathWithRelativePath() + { + $this->assertSame('_media/foo.txt', MediaFile::make('foo.txt')->path); + } + + public function testNormalizePathWithOutputDirectoryPath() + { + Hyde::setMediaDirectory('_custom_media'); + $this->assertSame('_custom_media/foo.txt', MediaFile::make('custom_media/foo.txt')->path); + Hyde::setMediaDirectory('_media'); // Reset to default + } + + public function testNormalizePathWithAlreadyCorrectFormat() + { + $this->assertSame('_media/foo.txt', MediaFile::make('_media/foo.txt')->path); + } + + public function testNormalizePathWithParentDirectoryReferences() + { + $this->assertSame('_media/foo.txt', MediaFile::make('../_media/foo.txt')->path); + $this->assertSame('_media/baz/../bar/foo.txt', MediaFile::make('_media/baz/../bar/foo.txt')->path); + } + public function testGetNameReturnsNameOfFile() { $this->assertSame('foo.txt', MediaFile::make('foo.txt')->getName()); From a6b83a8676efdc75677984ad7e8cdc6e4f899df2 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 15:11:58 +0200 Subject: [PATCH 80/88] Annotate context --- packages/framework/tests/Unit/Support/MediaFileUnitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php index 1585bfb6acd..7311819b2db 100644 --- a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php @@ -189,7 +189,7 @@ public function testNormalizePathWithAlreadyCorrectFormat() public function testNormalizePathWithParentDirectoryReferences() { $this->assertSame('_media/foo.txt', MediaFile::make('../_media/foo.txt')->path); - $this->assertSame('_media/baz/../bar/foo.txt', MediaFile::make('_media/baz/../bar/foo.txt')->path); + $this->assertSame('_media/baz/../bar/foo.txt', MediaFile::make('_media/baz/../bar/foo.txt')->path); // We don't do anything about this } public function testGetNameReturnsNameOfFile() From 53023b5e9653bf919adc8ea827db54075aff22be Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 15:13:14 +0200 Subject: [PATCH 81/88] Change protected properties to public readonly These are part of the public interface of the class, but the should be immutable since there is no way to change them (in terms of persisting modified states) --- packages/framework/src/Support/Filesystem/MediaFile.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index e5a2d910455..3b8a57a639c 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -28,9 +28,9 @@ class MediaFile extends ProjectFile /** @internal Controls whether to validate the existence of the file, intended for unit testing. Turning this off may lead to unexpected behavior. */ public static bool $validateExistence = true; - protected int $length; - protected string $mimeType; - protected string $hash; + public readonly int $length; + public readonly string $mimeType; + public readonly string $hash; public function __construct(string $path) { From a39ba5be66ec4c06f80c56b0c6d1626860a53f92 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 15:15:03 +0200 Subject: [PATCH 82/88] Normalize extension access between class structure --- packages/framework/src/Support/Filesystem/MediaFile.php | 2 +- packages/framework/src/Support/Filesystem/ProjectFile.php | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 3b8a57a639c..5ece5d24400 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -150,7 +150,7 @@ protected function findContentLength(): int protected function findMimeType(): string { - $extension = Filesystem::extension($this->getPath()); + $extension = $this->getExtension(); // See if we can find a mime type for the extension instead of // having to rely on a PHP extension and filesystem lookups. diff --git a/packages/framework/src/Support/Filesystem/ProjectFile.php b/packages/framework/src/Support/Filesystem/ProjectFile.php index eb29ba893e9..36376fbc14c 100644 --- a/packages/framework/src/Support/Filesystem/ProjectFile.php +++ b/packages/framework/src/Support/Filesystem/ProjectFile.php @@ -11,8 +11,6 @@ use Hyde\Support\Concerns\Serializable; use Hyde\Support\Contracts\SerializableContract; -use function pathinfo; - /** * Filesystem abstraction for a file stored in the project. */ @@ -71,6 +69,6 @@ public function getContents(): string public function getExtension(): string { - return pathinfo($this->getAbsolutePath(), PATHINFO_EXTENSION); + return Filesystem::extension($this->getPath()); } } From e077ac615146d125e09640caab4db9f805ecd85c Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Thu, 1 Aug 2024 21:25:08 +0200 Subject: [PATCH 83/88] Remove internal validate existence flag --- .../src/Support/Filesystem/MediaFile.php | 5 +---- .../Foundation/FilesystemHasMediaFilesTest.php | 9 +-------- .../tests/Unit/Support/MediaFileUnitTest.php | 16 ---------------- 3 files changed, 2 insertions(+), 28 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 5ece5d24400..184ea906821 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -25,9 +25,6 @@ class MediaFile extends ProjectFile /** @var array The default extensions for media types */ final public const EXTENSIONS = ['png', 'svg', 'jpg', 'jpeg', 'gif', 'ico', 'css', 'js']; - /** @internal Controls whether to validate the existence of the file, intended for unit testing. Turning this off may lead to unexpected behavior. */ - public static bool $validateExistence = true; - public readonly int $length; public readonly string $mimeType; public readonly string $hash; @@ -36,7 +33,7 @@ public function __construct(string $path) { $path = $this->normalizePath($path); - if (static::$validateExistence && Filesystem::missing($path)) { + if (Filesystem::missing($path)) { throw new FileNotFoundException($path); } diff --git a/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php b/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php index e23e7ad8177..d16f987b05a 100644 --- a/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php +++ b/packages/framework/tests/Unit/Foundation/FilesystemHasMediaFilesTest.php @@ -28,17 +28,10 @@ protected function setUp(): void $this->filesystem = new TestableFilesystem(Hyde::getInstance()); $mock = Mockery::mock(BaseFilesystem::class)->makePartial(); + $mock->shouldReceive('missing')->andReturn(false)->byDefault(); $mock->shouldReceive('size')->andReturn(100)->byDefault(); $mock->shouldReceive('hash')->andReturn('hash')->byDefault(); app()->instance(BaseFilesystem::class, $mock); - - MediaFile::$validateExistence = false; - } - - protected function tearDown(): void - { - parent::tearDown(); - MediaFile::$validateExistence = true; } public function testAssetsMethodReturnsSameInstanceOnSubsequentCalls() diff --git a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php index 7311819b2db..f07bf42cc61 100644 --- a/packages/framework/tests/Unit/Support/MediaFileUnitTest.php +++ b/packages/framework/tests/Unit/Support/MediaFileUnitTest.php @@ -45,8 +45,6 @@ protected function setUp(): void { parent::setUp(); - MediaFile::$validateExistence = false; - $this->mockFilesystem = Mockery::mock(BaseFilesystem::class); app()->instance(BaseFilesystem::class, $this->mockFilesystem); @@ -68,7 +66,6 @@ protected function tearDown(): void { parent::tearDown(); - MediaFile::$validateExistence = true; Mockery::close(); } @@ -147,15 +144,6 @@ public function testConstructorWithVariousInputFormats() $this->assertSame('_media/foo.txt', MediaFile::make('media/foo.txt')->path); } - public function testConstructorWithValidationDisabled() - { - MediaFile::$validateExistence = false; - $this->mockFilesystem->shouldReceive('missing')->never(); - - $file = new MediaFile('non_existent_file.txt'); - $this->assertInstanceOf(MediaFile::class, $file); - } - public function testConstructorSetsProperties() { $file = new MediaFile('foo.txt'); @@ -285,8 +273,6 @@ public function testGetHashReturnsHash() public function testExceptionIsThrownWhenConstructingFileThatDoesNotExist() { - MediaFile::$validateExistence = true; - $this->mockFilesystem->shouldReceive('missing') ->with(Hyde::path('_media/foo')) ->andReturn(true); @@ -299,8 +285,6 @@ public function testExceptionIsThrownWhenConstructingFileThatDoesNotExist() public function testExceptionIsNotThrownWhenConstructingFileThatDoesExist() { - MediaFile::$validateExistence = true; - $this->mockFilesystem->shouldReceive('missing') ->with(Hyde::path('_media/foo')) ->andReturn(false); From dbbd957aa568d8b769c300f366bc2845ad893b82 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 3 Aug 2024 12:36:10 +0200 Subject: [PATCH 84/88] Introduce local variable --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 184ea906821..3f25f8ea2c4 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -137,7 +137,9 @@ protected function normalizePath(string $path): string $path = '_'.$path; } - return static::sourcePath(trim_slashes(Str::after($path, Hyde::getMediaDirectory()))); + $path = static::sourcePath(trim_slashes(Str::after($path, Hyde::getMediaDirectory()))); + + return $path; } protected function findContentLength(): int From d3618469c42911a85d6171f53b4b06834ffaab3f Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 3 Aug 2024 12:36:31 +0200 Subject: [PATCH 85/88] Rename helper method --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 3f25f8ea2c4..b1728426a89 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -31,7 +31,7 @@ class MediaFile extends ProjectFile public function __construct(string $path) { - $path = $this->normalizePath($path); + $path = $this->getNormalizedPath($path); if (Filesystem::missing($path)) { throw new FileNotFoundException($path); @@ -128,7 +128,7 @@ public static function getCacheBustKey(string $file): string : ''; } - protected function normalizePath(string $path): string + protected function getNormalizedPath(string $path): string { $path = Hyde::pathToRelative($path); From e6ae28dbfc6f1171c280cf92231d09b934e3e05a Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 3 Aug 2024 12:37:47 +0200 Subject: [PATCH 86/88] Move file existence check to normalizer method --- packages/framework/src/Support/Filesystem/MediaFile.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index b1728426a89..ac2ee5da846 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -33,10 +33,6 @@ public function __construct(string $path) { $path = $this->getNormalizedPath($path); - if (Filesystem::missing($path)) { - throw new FileNotFoundException($path); - } - parent::__construct($path); $this->length = $this->findContentLength(); @@ -139,6 +135,10 @@ protected function getNormalizedPath(string $path): string $path = static::sourcePath(trim_slashes(Str::after($path, Hyde::getMediaDirectory()))); + if (Filesystem::missing($path)) { + throw new FileNotFoundException($path); + } + return $path; } From 89feb9c768146fc20f5a9587979cba6866b037a4 Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 3 Aug 2024 13:10:30 +0200 Subject: [PATCH 87/88] Document code reasoning --- packages/framework/src/Support/Filesystem/MediaFile.php | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index ac2ee5da846..67cc69117c2 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -133,6 +133,7 @@ protected function getNormalizedPath(string $path): string $path = '_'.$path; } + // Normalize the path to include the media directory $path = static::sourcePath(trim_slashes(Str::after($path, Hyde::getMediaDirectory()))); if (Filesystem::missing($path)) { From c3bcc78b3d6ae286dc2f40fa14eb8f0eb0d7722d Mon Sep 17 00:00:00 2001 From: Caen De Silva Date: Sat, 3 Aug 2024 13:10:54 +0200 Subject: [PATCH 88/88] Inline local variable --- packages/framework/src/Support/Filesystem/MediaFile.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/packages/framework/src/Support/Filesystem/MediaFile.php b/packages/framework/src/Support/Filesystem/MediaFile.php index 67cc69117c2..2c2835880b8 100644 --- a/packages/framework/src/Support/Filesystem/MediaFile.php +++ b/packages/framework/src/Support/Filesystem/MediaFile.php @@ -31,9 +31,7 @@ class MediaFile extends ProjectFile public function __construct(string $path) { - $path = $this->getNormalizedPath($path); - - parent::__construct($path); + parent::__construct($this->getNormalizedPath($path)); $this->length = $this->findContentLength(); $this->mimeType = $this->findMimeType();