• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

JBZoo / Codestyle / 8445177639

26 Mar 2024 08:28PM UTC coverage: 87.66% (-0.3%) from 87.967%
8445177639

push

github

web-flow
Update getFixerConfig method in PhpCsFixerCodingStandard (#50)

11 of 14 new or added lines in 1 file covered. (78.57%)

51 existing lines in 5 files now uncovered.

547 of 624 relevant lines covered (87.66%)

10.39 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

80.12
/src/PHPUnit/TraitReadme.php
1
<?php
2

3
/**
4
 * JBZoo Toolbox - Codestyle.
5
 *
6
 * This file is part of the JBZoo Toolbox project.
7
 * For the full copyright and license information, please view the LICENSE
8
 * file that was distributed with this source code.
9
 *
10
 * @license    MIT
11
 * @copyright  Copyright (C) JBZoo.com, All rights reserved.
12
 * @see        https://github.com/JBZoo/Codestyle
13
 */
14

15
declare(strict_types=1);
16

17
namespace JBZoo\Codestyle\PHPUnit;
18

19
use JBZoo\Markdown\Markdown;
20

21
use function JBZoo\PHPUnit\fail;
22
use function JBZoo\PHPUnit\isFileContains;
23
use function JBZoo\PHPUnit\isNotEmpty;
24
use function JBZoo\PHPUnit\success;
25

26
/**
27
 * @phan-file-suppress PhanUndeclaredProperty
28
 */
29
trait TraitReadme
30
{
31
    // See also
32
    // - https://github.com/badges/shields#specification
33
    // - https://github.com/badges/poser
34

35
    protected string $readmeFile = 'README.md';
36

37
    /** @var bool[] */
38
    protected array $params = [
39
        // Packagist
40
        'packagist_latest_stable_version'   => true,
41
        'packagist_latest_unstable_version' => true,
42
        'packagist_license'                 => true,
43
        'packagist_version'                 => true,
44

45
        'packagist_dependents' => true,
46
        'packagist_suggesters' => true,
47

48
        'packagist_downloads_total'   => true,
49
        'packagist_downloads_daily'   => true,
50
        'packagist_downloads_monthly' => true,
51

52
        'packagist_composerlock'  => true,
53
        'packagist_gitattributes' => true,
54

55
        'github_issues'  => true,
56
        'github_license' => true,
57
        'github_forks'   => true,
58
        'github_stars'   => true,
59
        'github_actions' => true,
60

61
        'docker_build' => false,
62
        'docker_pulls' => false,
63

64
        'strict_types' => false,
65
        'codecov'      => false,
66
        'scrutinizer'  => false,
67

68
        'psalm_coverage' => true,
69
        'psalm_level'    => true,
70
        'codacy'         => true,
71
        'codefactor'     => true,
72
        'sonarcloud'     => true,
73
        'coveralls'      => true,
74
        'circle_ci'      => true,
75
        'visitors'       => false,
76
    ];
77

78
    /** @var string[] */
79
    protected array $badgesTemplate = [
80
        'github_actions',
81
        'docker_build',
82
        'codecov',
83
        'coveralls',
84
        'psalm_coverage',
85
        'psalm_level',
86
        'codefactor',
87
        'scrutinizer',
88
        '__BR__',
89
        'packagist_latest_stable_version',
90
        'packagist_downloads_total',
91
        'docker_pulls',
92
        'packagist_dependents',
93
        'visitors',
94
        'github_license',
95
    ];
96

97
    protected string $codacyId = '__SEE_REPO_CONFIG__';
98

99
    // ### Test cases ##################################################################################################
100

101
    public function testReadmeHeader(): void
102
    {
103
        $expectedBadges = [];
6✔
104

105
        foreach ($this->badgesTemplate as $badgeName) {
6✔
106
            if ($badgeName === '__BR__') {
6✔
107
                $expectedBadges[$badgeName] = "\n";
6✔
108
            } else {
109
                $testMethod = 'checkBadge' . \str_replace('_', '', \ucwords($badgeName, '_'));
6✔
110

111
                if (\method_exists($this, $testMethod)) {
6✔
112
                    /** @phpstan-ignore-next-line */
113
                    $tmpBadge = $this->{$testMethod}();
6✔
114
                    if ($tmpBadge !== null) {
6✔
115
                        $expectedBadges[$badgeName] = "{$tmpBadge}    ";
6✔
116
                    }
117
                } else {
118
                    fail("Method not found: '{$testMethod}'");
×
119
                }
120
            }
121
        }
122

123
        $expectedBadgeLine = \implode("\n", [
6✔
124
            $this->getTitle(),
6✔
125
            '',
3✔
126
            \trim(\implode('', \array_filter($expectedBadges))),
6✔
127
            '',
3✔
128
            '',
3✔
129
        ]);
3✔
130

131
        isFileContains($expectedBadgeLine, PROJECT_ROOT . '/README.md');
6✔
132
    }
133

134
    protected function getTitle(): string
135
    {
136
        return "# {$this->vendorName} / {$this->packageName}";
6✔
137
    }
138

139
    // ### Bages #######################################################################################################
140

141
    protected function checkBadgePackagistLatestStableVersion(): ?string
142
    {
143
        return $this->getPreparedBadge($this->getBadgePackagist('Stable Version', 'version'));
6✔
144
    }
145

146
    protected function checkBadgePackagistLatestUnstableVersion(): ?string
147
    {
148
        return $this->getPreparedBadge($this->getBadgePackagist('Latest Unstable Version', 'v/unstable'));
×
149
    }
150

151
    protected function checkBadgePackagistDownloadsTotal(): ?string
152
    {
153
        return $this->getPreparedBadge($this->getBadgePackagist('Total Downloads', 'downloads', 'stats'));
6✔
154
    }
155

156
    protected function checkBadgePackagistLicense(): ?string
157
    {
158
        return $this->getPreparedBadge($this->getBadgePackagist('License', 'license'));
×
159
    }
160

161
    protected function checkBadgePackagistDownloadsMonthly(): ?string
162
    {
163
        return $this->getPreparedBadge($this->getBadgePackagist('Monthly Downloads', 'd/monthly', 'stats'));
×
164
    }
165

166
    protected function checkBadgePackagistDownloadsDaily(): ?string
167
    {
168
        return $this->getPreparedBadge($this->getBadgePackagist('Daily Downloads', 'd/daily', 'stats'));
×
169
    }
170

171
    protected function checkBadgePackagistVersion(): ?string
172
    {
173
        return $this->getPreparedBadge($this->getBadgePackagist('Version', 'version'));
×
174
    }
175

176
    protected function checkBadgePackagistComposerlock(): ?string
177
    {
178
        return $this->getPreparedBadge($this->getBadgePackagist('Version', 'composerlock'));
×
179
    }
180

181
    protected function checkBadgePackagistGitAttributes(): ?string
182
    {
183
        return $this->getPreparedBadge($this->getBadgePackagist('.gitattributes', 'gitattributes'));
×
184
    }
185

186
    protected function checkBadgePackagistDependents(): ?string
187
    {
188
        return $this->getPreparedBadge(
6✔
189
            $this->getBadgePackagist('Dependents', 'dependents', 'dependents?order_by=downloads'),
6✔
190
        );
3✔
191
    }
192

193
    protected function checkBadgePackagistSuggesters(): ?string
194
    {
195
        return $this->getPreparedBadge($this->getBadgePackagist('Suggesters', 'suggesters'));
×
196
    }
197

198
    protected function checkBadgeCircleCI(): ?string
199
    {
200
        return $this->getPreparedBadge($this->getBadgePackagist('CircleCI Build', 'circleci'));
×
201
    }
202

203
    protected function checkBadgeCoveralls(): ?string
204
    {
205
        return $this->getPreparedBadge(
6✔
206
            $this->getBadge(
6✔
207
                'Coverage Status',
3✔
208
                'https://coveralls.io/repos/github/__VENDOR_ORIG__/__PACKAGE_ORIG__/badge.svg?branch=master',
3✔
209
                'https://coveralls.io/github/__VENDOR_ORIG__/__PACKAGE_ORIG__?branch=master',
3✔
210
            ),
3✔
211
        );
3✔
212
    }
213

214
    protected function checkBadgeCodacy(): ?string
215
    {
216
        return $this->getPreparedBadge(
×
217
            $this->getBadge(
×
UNCOV
218
                'Codacy Badge',
219
                "https://app.codacy.com/project/badge/Grade/{$this->codacyId}",
×
UNCOV
220
                'https://www.codacy.com/gh/__VENDOR__/__PACKAGE__',
UNCOV
221
            ),
UNCOV
222
        );
223
    }
224

225
    protected function checkBadgePsalmCoverage(): ?string
226
    {
227
        return $this->getPreparedBadge(
6✔
228
            $this->getBadge(
6✔
229
                'Psalm Coverage',
3✔
230
                'https://shepherd.dev/github/__VENDOR_ORIG__/__PACKAGE_ORIG__/coverage.svg',
3✔
231
                'https://shepherd.dev/github/__VENDOR_ORIG__/__PACKAGE_ORIG__',
3✔
232
            ),
3✔
233
        );
3✔
234
    }
235

236
    protected function checkBadgePsalmLevel(): ?string
237
    {
238
        return $this->getPreparedBadge(
6✔
239
            $this->getBadge(
6✔
240
                'Psalm Level',
3✔
241
                'https://shepherd.dev/github/__VENDOR_ORIG__/__PACKAGE_ORIG__/level.svg',
3✔
242
                'https://shepherd.dev/github/__VENDOR_ORIG__/__PACKAGE_ORIG__',
3✔
243
            ),
3✔
244
        );
3✔
245
    }
246

247
    protected function checkBadgeGithubIssues(): ?string
248
    {
249
        return $this->getPreparedBadge(
×
250
            $this->getBadge(
×
UNCOV
251
                'GitHub Issues',
UNCOV
252
                'https://img.shields.io/github/issues/__VENDOR__/__PACKAGE__',
UNCOV
253
                'https://github.com/__VENDOR_ORIG__/__PACKAGE_ORIG__/issues',
UNCOV
254
            ),
UNCOV
255
        );
256
    }
257

258
    protected function checkBadgeGithubForks(): ?string
259
    {
260
        return $this->getPreparedBadge(
×
261
            $this->getBadge(
×
UNCOV
262
                'GitHub Forks',
UNCOV
263
                'https://img.shields.io/github/forks/__VENDOR__/__PACKAGE__',
UNCOV
264
                'https://github.com/__VENDOR_ORIG__/__PACKAGE_ORIG__/network',
UNCOV
265
            ),
UNCOV
266
        );
267
    }
268

269
    protected function checkBadgeGithubStars(): ?string
270
    {
271
        return $this->getPreparedBadge(
×
272
            $this->getBadge(
×
UNCOV
273
                'GitHub Stars',
UNCOV
274
                'https://img.shields.io/github/stars/__VENDOR__/__PACKAGE__',
UNCOV
275
                'https://github.com/__VENDOR_ORIG__/__PACKAGE_ORIG__/stargazers',
UNCOV
276
            ),
UNCOV
277
        );
278
    }
279

280
    protected function checkBadgeGithubLicense(): ?string
281
    {
282
        return $this->getPreparedBadge(
6✔
283
            $this->getBadge(
6✔
284
                'GitHub License',
3✔
285
                'https://img.shields.io/github/license/__VENDOR__/__PACKAGE__',
3✔
286
                'https://github.com/__VENDOR_ORIG__/__PACKAGE_ORIG__/blob/master/LICENSE',
3✔
287
            ),
3✔
288
        );
3✔
289
    }
290

291
    protected function checkBadgeDockerBuild(): ?string
292
    {
293
        return $this->getPreparedBadge(
6✔
294
            $this->getBadge(
6✔
295
                'Docker Cloud Build Status',
3✔
296
                'https://img.shields.io/docker/cloud/build/__VENDOR__/__PACKAGE__.svg',
3✔
297
                'https://hub.docker.com/r/__VENDOR__/__PACKAGE__',
3✔
298
            ),
3✔
299
        );
3✔
300
    }
301

302
    protected function checkBadgeDockerPulls(): ?string
303
    {
304
        return $this->getPreparedBadge(
6✔
305
            $this->getBadge(
6✔
306
                'Docker Pulls',
3✔
307
                'https://img.shields.io/docker/pulls/__VENDOR__/__PACKAGE__.svg',
3✔
308
                'https://hub.docker.com/r/__VENDOR__/__PACKAGE__',
3✔
309
            ),
3✔
310
        );
3✔
311
    }
312

313
    protected function checkBadgeScrutinizer(): ?string
314
    {
315
        return $this->getPreparedBadge(
6✔
316
            $this->getBadge(
6✔
317
                'Scrutinizer Code Quality',
3✔
318
                'https://scrutinizer-ci.com/g/__VENDOR__/__PACKAGE__/badges/quality-score.png?b=master',
3✔
319
                'https://scrutinizer-ci.com/g/__VENDOR__/__PACKAGE__/?branch=master',
3✔
320
            ),
3✔
321
        );
3✔
322
    }
323

324
    protected function checkBadgeCodefactor(): ?string
325
    {
326
        return $this->getPreparedBadge(
6✔
327
            $this->getBadge(
6✔
328
                'CodeFactor',
3✔
329
                'https://www.codefactor.io/repository/github/__VENDOR__/__PACKAGE__/badge',
3✔
330
                'https://www.codefactor.io/repository/github/__VENDOR__/__PACKAGE__/issues',
3✔
331
            ),
3✔
332
        );
3✔
333
    }
334

335
    protected function checkBadgeSonarcloud(): ?string
336
    {
337
        $project = '__VENDOR_ORIG_____PACKAGE_ORIG__';
×
338

339
        return $this->getPreparedBadge(
×
340
            $this->getBadge(
×
UNCOV
341
                'Quality Gate Status',
342
                "https://sonarcloud.io/api/project_badges/measure?project={$project}&metric=alert_status",
×
343
                "https://sonarcloud.io/dashboard?id={$project}",
×
UNCOV
344
            ),
UNCOV
345
        );
346
    }
347

348
    protected function checkBadgeStrictTypes(): ?string
349
    {
350
        return $this->getPreparedBadge(
×
351
            $this->getBadge(
×
UNCOV
352
                'PHP Strict Types',
UNCOV
353
                'https://img.shields.io/badge/strict__types-%3D1-brightgreen',
UNCOV
354
                'https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.strict',
UNCOV
355
            ),
UNCOV
356
        );
357
    }
358

359
    protected function getBadgePackagist(string $name, string $mode, ?string $postfix = null): string
360
    {
361
        return $this->getBadge(
6✔
362
            $name,
3✔
363
            "https://poser.pugx.org/__VENDOR__/__PACKAGE__/{$mode}",
6✔
364
            'https://packagist.org/packages/__VENDOR__/__PACKAGE__' . ($postfix !== '' ? "/{$postfix}" : ''),
6✔
365
        );
3✔
366
    }
367

368
    protected function checkBadgeCodecov(): ?string
369
    {
370
        return $this->getPreparedBadge(
6✔
371
            $this->getBadge(
6✔
372
                'codecov',
3✔
373
                'https://codecov.io/gh/__VENDOR_ORIG__/__PACKAGE_ORIG__/branch/master/graph/badge.svg',
3✔
374
                'https://codecov.io/gh/__VENDOR_ORIG__/__PACKAGE_ORIG__/branch/master',
3✔
375
            ),
3✔
376
        );
3✔
377
    }
378

379
    protected function checkBadgePhpVersion(): ?string
380
    {
381
        return $this->getPreparedBadge(
×
382
            $this->getBadge(
×
UNCOV
383
                'PHP Version',
UNCOV
384
                'https://img.shields.io/packagist/php-v/__VENDOR__/__PACKAGE__',
UNCOV
385
                'https://github.com/__VENDOR_ORIG__/__PACKAGE_ORIG__/blob/master/composer.json',
UNCOV
386
            ),
UNCOV
387
        );
388
    }
389

390
    protected function checkBadgeGithubActions(): ?string
391
    {
392
        $path = 'https://github.com/__VENDOR_ORIG__/__PACKAGE_ORIG__/actions/workflows';
6✔
393

394
        return $this->getPreparedBadge(
6✔
395
            $this->getBadge(
6✔
396
                'CI',
3✔
397
                $path . '/main.yml/badge.svg?branch=master',
6✔
398
                $path . '/main.yml?query=branch%3Amaster',
6✔
399
            ),
3✔
400
        );
3✔
401
    }
402

403
    protected function checkBadgeVisitors(): ?string
404
    {
405
        return $this->getPreparedBadge(
6✔
406
            $this->getBadge(
6✔
407
                'Visitors',
3✔
408
                'https://visitor-badge.glitch.me/badge?page_id=__VENDOR__.__PACKAGE__',
3✔
409
            ),
3✔
410
        );
3✔
411
    }
412

413
    // // Tools ////////////////////////////////////////////////////////////////////////////////////////////////////////
414

415
    protected function getBadge(string $name, string $svgUrl, string $linkUrl = ''): string
416
    {
417
        /** @var string[] $params */
418
        $params = [
6✔
419
            '__NAME__'         => $name,
3✔
420
            '__SVG_URL__'      => $svgUrl,
3✔
421
            '__SERVICE_URL__'  => $linkUrl,
3✔
422
            '__VENDOR_ORIG__'  => $this->vendorName,
6✔
423
            '__PACKAGE_ORIG__' => $this->packageName,
6✔
424
            '__VENDOR__'       => \strtolower($this->vendorName),
6✔
425
            '__PACKAGE__'      => \strtolower($this->packageName),
6✔
426
        ];
3✔
427

428
        $result = (string)Markdown::badge('__NAME__', '__SVG_URL__', '__SERVICE_URL__');
6✔
429

430
        foreach ($params as $key => $value) {
6✔
431
            $result = \str_replace($key, $value, $result);
6✔
432
        }
433

434
        return $result;
6✔
435
    }
436

437
    protected function getPreparedBadge(string $badge): ?string
438
    {
439
        $trace        = \debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS);
6✔
440
        $testCaseName = \str_replace('check_badge_', '', self::splitCamelCase($trace[1]['function']));
6✔
441
        $isEnabled    = $this->params[$testCaseName] ?? null;
6✔
442

443
        if ($isEnabled === null) {
6✔
444
            return null;
×
445
        }
446

447
        if (!$isEnabled) {
6✔
448
            success();
6✔
449

450
            return null;
6✔
451
        }
452

453
        return $badge;
6✔
454
    }
455

456
    protected static function getReadme(): string
457
    {
458
        $content = (string)\file_get_contents(PROJECT_ROOT . '/README.md');
×
459
        isNotEmpty($content);
×
460

461
        return $content;
×
462
    }
463

464
    protected static function splitCamelCase(string $input): string
465
    {
466
        $original = $input;
6✔
467

468
        $output = (string)\preg_replace(['/(?<=[^A-Z])([A-Z])/', '/(?<=[^0-9])([0-9])/'], '_$0', $input);
6✔
469
        $output = (string)\preg_replace('#_{1,}#', '_', $output);
6✔
470

471
        $output = \trim($output);
6✔
472
        $output = \strtolower($output);
6✔
473

474
        if ($output === '') {
6✔
475
            return $original;
×
476
        }
477

478
        return $output;
6✔
479
    }
480
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc