Skip to content

Commit f212621

Browse files
authored
Add infection check (#12)
* Install infection * Add infection check * Fix php version as 8.1
1 parent af503e1 commit f212621

File tree

10 files changed

+247
-45
lines changed

10 files changed

+247
-45
lines changed

.github/workflows/php.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ jobs:
1414
strategy:
1515
fail-fast: true
1616
matrix:
17-
php-versions: ['8.0', '8.1']
17+
php-versions: ['8.1']
1818

1919
steps:
2020
- uses: actions/checkout@v2
@@ -43,8 +43,11 @@ jobs:
4343
if: steps.composer-cache.outputs.cache-hit != 'true'
4444
run: composer install --prefer-dist --no-progress --no-suggest
4545

46+
- name: Run linters
47+
run: composer run-script linter
48+
4649
- name: Run test suite
4750
run: composer run-script test
4851

49-
- name: Run linters
50-
run: composer run-script linter
52+
- name: Run infection testing
53+
run: composer run-script infection

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ composer.lock
88
tests/coverage
99
docker/.env
1010
test.php
11+
infection.log
1112

1213
.~lock.*

Makefile

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
user_id := $(shell id -u)
44
docker_compose_bin := $(shell command -v docker-compose 2> /dev/null) --file "docker/docker-compose.yml"
55
php_container_bin := $(docker_compose_bin) run --rm -u "$(user_id)" "php"
6+
composer_bin := $(php_container_bin) composer run-script
67

7-
.PHONY : help build install shell fixer test coverage
88
.DEFAULT_GOAL := build
99

1010
# --- [ Development tasks ] -------------------------------------------------------------------------------------------
@@ -19,13 +19,22 @@ shell: ## Runs shell in container
1919
$(php_container_bin) bash
2020

2121
fixer: ## Run fixer to fix code style
22-
$(php_container_bin) composer run-script fixer
22+
$(composer_bin) fixer
2323

2424
linter: ## Run linter to check project
25-
$(php_container_bin) composer run-script linter
25+
$(composer_bin) linter
2626

2727
test: ## Run tests
28-
$(php_container_bin) composer run-script test
28+
$(composer_bin) test
2929

3030
coverage: ## Run tests with coverage
31-
$(php_container_bin) composer run-script coverage
31+
$(composer_bin) coverage
32+
33+
infection: ## Run infection testing
34+
$(composer_bin) infection
35+
36+
release: ## Run all preparations before release
37+
$(composer_bin) fixer
38+
$(composer_bin) linter
39+
$(composer_bin) test
40+
$(composer_bin) infection

composer.json

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,15 @@
55
"keywords": ["php", "file system"],
66
"license": "MIT",
77
"require": {
8-
"php": ">=8.0"
8+
"php": ">=8.1"
99
},
1010
"require-dev": {
1111
"phpunit/phpunit": "^9.0",
1212
"friendsofphp/php-cs-fixer": "^3.0",
1313
"sebastian/phpcpd": "^6.0",
1414
"vimeo/psalm": "^4.0",
15-
"psalm/plugin-phpunit": "^0.16"
15+
"psalm/plugin-phpunit": "^0.16",
16+
"infection/infection": "^0.26.13"
1617
},
1718
"autoload": {
1819
"psr-4": {
@@ -35,15 +36,23 @@
3536
"vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -vv --allow-risky=yes"
3637
],
3738
"linter": [
38-
"vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -vv --allow-risky=yes --dry-run --stop-on-violation",
39-
"vendor/bin/phpcpd ./ --exclude vendor --exclude tests",
40-
"vendor/bin/psalm --show-info=true --php-version=$(php -r \"echo phpversion();\")"
39+
"vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -vv --allow-risky=yes --dry-run --stop-on-violation",
40+
"vendor/bin/phpcpd ./ --exclude vendor --exclude tests",
41+
"vendor/bin/psalm --show-info=true --php-version=$(php -r \"echo phpversion();\")"
42+
],
43+
"infection": [
44+
"vendor/bin/infection --min-msi=100 --min-covered-msi=100 --threads=8"
4145
]
4246
},
4347
"repositories": [
4448
{
4549
"type": "git",
4650
"url": "https://github.com/marvin255/file-system-helper"
4751
}
48-
]
52+
],
53+
"config": {
54+
"allow-plugins": {
55+
"infection/extension-installer": false
56+
}
57+
}
4958
}

docker/php/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ RUN docker-php-ext-install zip soap \
2424
&& echo 'xdebug.mode=coverage' >> /usr/local/etc/php/conf.d/docker-php-ext-xdebug.ini
2525

2626

27-
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer --version=2.3.7 \
27+
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer --version=2.4.2 \
2828
&& mkdir -p /.composer && chmod -Rf 777 /.composer
2929

3030

infection.json

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{
2+
"$schema": "vendor/infection/infection/resources/schema.json",
3+
"source": {
4+
"directories": [
5+
"src"
6+
]
7+
},
8+
"logs": {
9+
"text": "infection.log"
10+
},
11+
"mutators": {
12+
"@default": true,
13+
"Throw_": {
14+
"ignore": [
15+
"Marvin255\\FileSystemHelper\\FileSystemHelperBase::getTmpDir",
16+
"Marvin255\\FileSystemHelper\\FileSystemHelperBase::copy",
17+
"Marvin255\\FileSystemHelper\\FileSystemHelperBase::rename",
18+
"Marvin255\\FileSystemHelper\\FileSystemHelperBase::runPhpFunction"
19+
]
20+
},
21+
"LogicalOr": {
22+
"ignore": [
23+
"Marvin255\\FileSystemHelper\\FileSystemHelperBase::getTmpDir"
24+
]
25+
},
26+
"TrueValue": {
27+
"ignore": [
28+
"Marvin255\\FileSystemHelper\\FileSystemHelperBase::mkdir"
29+
]
30+
}
31+
}
32+
}

phpunit.xml.dist

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<?xml version="1.0" encoding="UTF-8"?>
2-
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" bootstrap="./vendor/autoload.php" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
2+
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" colors="true" bootstrap="./vendor/autoload.php" executionOrder="random" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/9.3/phpunit.xsd">
33
<coverage>
44
<include>
55
<directory>./src</directory>

src/FileSystemHelperBase.php

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,32 @@
1212
/**
1313
* Object to manipulate files and folders.
1414
*/
15-
class FileSystemHelperBase implements FileSystemHelper
15+
final class FileSystemHelperBase implements FileSystemHelper
1616
{
17-
private ?string $baseFolder;
17+
private readonly ?string $baseFolder;
1818

1919
public function __construct(?string $baseFolder = null)
2020
{
21+
$validatedBaseFolder = null;
22+
2123
if ($baseFolder !== null) {
22-
$baseFolder = str_replace(
23-
['\\', '/'],
24-
\DIRECTORY_SEPARATOR,
25-
trim($baseFolder)
26-
);
27-
}
24+
$validatedBaseFolder = str_replace(['\\', '/'], \DIRECTORY_SEPARATOR, trim($baseFolder));
25+
if ($validatedBaseFolder === '') {
26+
throw $this->createException(
27+
"Base folder can't be empty. Set non empty string or null"
28+
);
29+
}
2830

29-
if ($baseFolder === '') {
30-
throw $this->createException(
31-
"Base folder can't be empty. Set non empty string or null"
32-
);
31+
$validatedBaseFolder = realpath($validatedBaseFolder);
32+
if ($validatedBaseFolder === false) {
33+
throw $this->createException(
34+
"Base folder '%s' doesn't exist",
35+
$baseFolder
36+
);
37+
}
3338
}
3439

35-
$this->baseFolder = $baseFolder;
40+
$this->baseFolder = $validatedBaseFolder;
3641
}
3742

3843
/**
@@ -204,6 +209,9 @@ public function mkdir(SplFileInfo|string $path, int $mode = 0777): SplFileInfo
204209
true
205210
);
206211

212+
// recoursive directory creation sometimes can't set permissions for nested folder
213+
chmod($dir->getPathname(), $mode);
214+
207215
return $dir;
208216
}
209217

@@ -228,7 +236,12 @@ public function emptyDir(SplFileInfo|string $path): void
228236
{
229237
$dir = $this->makeFileInfoAndCheckBasePath($path);
230238

231-
if (!$dir->isDir()) {
239+
if ($dir->isFile()) {
240+
throw $this->createException(
241+
"Can't empty directory '%s' because it's a file",
242+
$dir
243+
);
244+
} elseif (!$dir->isDir()) {
232245
throw $this->createException(
233246
"Directory '%s' must exist to be emptied",
234247
$dir
@@ -320,7 +333,7 @@ private function makeFileInfoAndCheckBasePath(SplFileInfo|string $data): SplFile
320333
{
321334
$data = $this->makeFileInfo($data);
322335

323-
if ($this->baseFolder !== null && mb_strpos($data->getPathName(), $this->baseFolder) !== 0) {
336+
if ($this->baseFolder !== null && strpos($data->getPathName(), $this->baseFolder) !== 0) {
324337
throw $this->createException(
325338
"Not allowed path '%s'. All paths must be within base directory '%s'",
326339
$data,
@@ -341,9 +354,7 @@ private function makeFileInfoAndCheckBasePath(SplFileInfo|string $data): SplFile
341354
*/
342355
private function runPhpFunction(string $functionName, ...$params): void
343356
{
344-
$res = (bool) \call_user_func_array($functionName, $params);
345-
346-
if (!$res) {
357+
if (\call_user_func_array($functionName, $params) === false) {
347358
throw $this->createException(
348359
"Got false result from '%s' function",
349360
$functionName
@@ -361,14 +372,10 @@ private function runPhpFunction(string $functionName, ...$params): void
361372
*/
362373
private function createException(string $message, ...$params): FileSystemException
363374
{
364-
$stringifyParams = array_map(
365-
fn (SplFileInfo|string $item): string => $item instanceof SplFileInfo ? $item->getPathName() : $item,
366-
$params
367-
);
375+
array_unshift($params, $message);
368376

369-
$message = rtrim($message, '.') . '.';
370-
array_unshift($stringifyParams, $message);
371-
$compiledMessage = (string) \call_user_func_array('sprintf', $stringifyParams);
377+
/** @var string */
378+
$compiledMessage = \call_user_func_array('sprintf', $params);
372379

373380
return new FileSystemException($compiledMessage);
374381
}

tests/BaseCase.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ protected function getTempDir(): string
3636
"Can't find or write temporary folder: {$this->tempDir}"
3737
);
3838
}
39-
$this->tempDir .= \DIRECTORY_SEPARATOR . 'fias_component';
39+
$this->tempDir .= \DIRECTORY_SEPARATOR . md5(random_bytes(20));
4040
$this->removeDir($this->tempDir);
4141
if (!mkdir($this->tempDir, 0777, true)) {
4242
throw new RuntimeException(
@@ -63,7 +63,7 @@ protected function getPathToTestDir(string $name = ''): string
6363
$name = md5(random_bytes(10));
6464
}
6565

66-
if (strpos($name, $this->getTempDir()) === 0) {
66+
if (strpos($name, $this->getTempDir() . \DIRECTORY_SEPARATOR) === 0) {
6767
$pathToFolder = $name;
6868
} else {
6969
$pathToFolder = $this->getTempDir() . \DIRECTORY_SEPARATOR . $name;
@@ -143,4 +143,11 @@ protected function tearDown(): void
143143

144144
parent::tearDown();
145145
}
146+
147+
protected function assertDirectoryHasPermissions(int $awaitedPermissions, string $directory): void
148+
{
149+
$awaitedPermissions = sprintf('%o', $awaitedPermissions);
150+
$realPermissions = substr(sprintf('%o', fileperms($directory)), -3);
151+
$this->assertSame($awaitedPermissions, $realPermissions, 'Directory has correct permissions');
152+
}
146153
}

0 commit comments

Comments
 (0)