diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 90b57ca..3bea429 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,23 +1,27 @@ -name: Pull Request Check +name: ๐Ÿš€ Pull Request Check ๐Ÿ” on: [pull_request] jobs: unit-test: - name: Unit testing + name: ๐Ÿงช Unit Testing - PHP ${{ matrix.php }} on ${{ matrix.os }} strategy: fail-fast: false matrix: - php: [7.4, 8.0, 8.1, 8.2, 8.3, 8.4, 8.5] - runs-on: ubuntu-latest + php: ['7.4', '8.0', '8.1', '8.2', '8.3', '8.4', '8.5'] + os: [ubuntu-latest, windows-latest, macos-latest] + runs-on: ${{ matrix.os }} steps: - - name: Checkout repository - uses: actions/checkout@v4 + - name: ๐Ÿ“‚ Checkout repository + uses: actions/checkout@v6 with: fetch-depth: 0 - - uses: shivammathur/setup-php@v2 + - name: ๐Ÿ˜ Setup PHP ${{ matrix.php }} + uses: shivammathur/setup-php@v2 with: php-version: ${{ matrix.php }} - extensions: curl, mbstring + extensions: mbstring, pdo_sqlite, fileinfo tools: composer:v2 - - run: composer install - - run: composer test + - name: ๐Ÿ“ฆ Install dependencies and ๐Ÿงช Run tests + run: | + composer install --no-progress --no-ansi -n + composer test -- --colors=never --no-interaction diff --git a/composer.json b/composer.json index 33d2951..30ccfca 100644 --- a/composer.json +++ b/composer.json @@ -45,6 +45,8 @@ } }, "require-dev": { + "ext-mbstring": "*", + "ext-fileinfo": "*", "ext-pdo_sqlite": "*", "flightphp/container": "^1.3", "flightphp/runway": "^1.2", diff --git a/flight/net/UploadedFile.php b/flight/net/UploadedFile.php index 61b4697..5fc10d0 100644 --- a/flight/net/UploadedFile.php +++ b/flight/net/UploadedFile.php @@ -131,14 +131,15 @@ public function moveTo(string $targetPath): void throw new Exception($this->getUploadErrorMessage($this->error)); } - if (is_writeable(dirname($targetPath)) === false) { - throw new Exception('Target directory is not writable'); - } - // Prevent path traversal attacks if (strpos($targetPath, '..') !== false) { throw new Exception('Invalid target path: contains directory traversal'); } + + if (is_writeable(dirname($targetPath)) === false) { + throw new Exception('Target directory is not writable'); + } + // Prevent absolute paths (basic check for Unix/Windows) if ($targetPath[0] === '/' || (strlen($targetPath) > 1 && $targetPath[1] === ':')) { throw new Exception('Invalid target path: absolute paths not allowed'); diff --git a/tests/RenderTest.php b/tests/RenderTest.php index ab71965..96203fb 100644 --- a/tests/RenderTest.php +++ b/tests/RenderTest.php @@ -29,8 +29,12 @@ public function testRenderView(): void public function testRenderLayout(): void { $this->app->render('hello', ['name' => 'Bob'], 'content'); + ob_start(); $this->app->render('layouts/layout'); + $html = ob_get_clean(); + $html = str_replace(["\r\n", "\n"], '', $html); + echo $html; - $this->expectOutputString("Hello, Bob!\n"); + $this->expectOutputString("Hello, Bob!"); } } diff --git a/tests/SimplePdoTest.php b/tests/SimplePdoTest.php index eb6d16d..4e97dd7 100644 --- a/tests/SimplePdoTest.php +++ b/tests/SimplePdoTest.php @@ -171,9 +171,9 @@ public function testFetchRowDoesNotAddLimitAfterReturningClause(): void $this->assertInstanceOf(Collection::class, $row); $this->assertSame('Alice', $row['name']); } catch (PDOException $exception) { - $this->assertSame( - 'Prepare failed: near "RETURNING": syntax error', - $exception->getMessage(), + $this->assertStringContainsString( + 'near "returning": syntax error', + strtolower($exception->getMessage()), ); } } diff --git a/tests/UploadedFileTest.php b/tests/UploadedFileTest.php index 1085e9b..752780d 100644 --- a/tests/UploadedFileTest.php +++ b/tests/UploadedFileTest.php @@ -114,6 +114,10 @@ public function testMoveToOverwrite(): void public function testMoveToSymlinkNonPost(): void { + if (PHP_OS === 'WINNT') { + $this->markTestSkipped('Symbolic links require special privileges on Windows.'); + } + file_put_contents('real_file', 'test'); if (file_exists('tmp_symlink')) { unlink('tmp_symlink'); diff --git a/tests/ViewTest.php b/tests/ViewTest.php index 54a0939..e57afd0 100644 --- a/tests/ViewTest.php +++ b/tests/ViewTest.php @@ -102,9 +102,13 @@ public function testTemplateWithCustomExtension(): void $this->view->set('name', 'Bob'); $this->view->extension = '.html'; + ob_start(); $this->view->render('world'); + $html = ob_get_clean(); + $html = str_replace(["\r\n", "\n"], '', $html); + echo $html; - $this->expectOutputString("Hello world, Bob!\n"); + $this->expectOutputString("Hello world, Bob!"); } public function testGetTemplateAbsolutePath(): void diff --git a/tests/commands/RouteCommandTest.php b/tests/commands/RouteCommandTest.php index 3aea0b1..26a8ba0 100644 --- a/tests/commands/RouteCommandTest.php +++ b/tests/commands/RouteCommandTest.php @@ -123,8 +123,8 @@ public function testGetRoutes(): void output; // phpcs:ignore $this->assertStringContainsString( - str_replace(PHP_EOL, '', $expected), - str_replace(PHP_EOL, '', $this->removeColors(file_get_contents(static::$ou))), + str_replace(["\r\n", "\n"], '', $expected), + str_replace(["\r\n", "\n"], '', $this->removeColors(file_get_contents(static::$ou))), ); }