Skip to content

Commit 3357517

Browse files
authored
Merge pull request #54 from voku/copilot/integrate-infection-into-ci-pipeline
Raise Infection from no-op to enforced signal and cover newly exposed mutation gaps
2 parents 3aa0507 + 3b374b2 commit 3357517

6 files changed

Lines changed: 89 additions & 1 deletion

File tree

.github/workflows/ci.yml

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,13 @@ jobs:
5151
composer: basic
5252
phpunit: '^9.6'
5353
phpunit_config: phpunit.xml.dist
54+
run_infection: true
5455
- php: '8.4'
5556
composer: basic
5657
phpunit: '^9.6'
5758
phpunit_config: phpunit.xml.dist
58-
timeout-minutes: 10
59+
# Infection mutates and re-runs the suite, so that leg needs a longer timeout.
60+
timeout-minutes: ${{ matrix.run_infection && 30 || 10 }}
5961
steps:
6062
- name: Checkout code
6163
uses: actions/checkout@v4
@@ -84,6 +86,10 @@ jobs:
8486
- name: Install dependencies
8587
run: |
8688
composer require --dev --no-update "phpunit/phpunit:${{ matrix.phpunit }}"
89+
if [[ "${{ matrix.run_infection }}" == "true" ]]; then
90+
composer config --no-plugins allow-plugins.infection/extension-installer false
91+
composer require --dev --no-update "infection/infection:^0.32.7"
92+
fi
8793
if [[ "${{ matrix.composer }}" == "lowest" ]]; then
8894
composer update --prefer-dist --no-interaction --prefer-lowest --prefer-stable
8995
fi;
@@ -105,6 +111,16 @@ jobs:
105111
run: |
106112
php vendor/bin/phpstan analyse
107113
114+
- name: Run infection with phpstan integration
115+
if: ${{ matrix.run_infection == true }}
116+
run: |
117+
XDEBUG_MODE=coverage php vendor/bin/infection \
118+
--configuration=infection.json.dist \
119+
--threads=max \
120+
--ignore-msi-with-no-mutations \
121+
--only-covering-test-cases \
122+
--logger-github
123+
108124
- name: Upload coverage results to Coveralls
109125
if: ${{ matrix.php == '8.3' }}
110126
continue-on-error: true

infection.json.dist

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
{
2+
"$schema": "https://infection.github.io/schema.json",
3+
"source": {
4+
"directories": [
5+
"src"
6+
],
7+
"excludes": [
8+
"src/JsonSerializableReturnTypeTraitPhp81.php"
9+
]
10+
},
11+
"phpUnit": {
12+
"configDir": "."
13+
},
14+
"staticAnalysisTool": "phpstan",
15+
"staticAnalysisToolOptions": "--memory-limit=512M",
16+
"minMsi": 87,
17+
"minCoveredMsi": 87
18+
}

src/CollectionStringy.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ public static function create(
3535
string $iteratorClass = \Arrayy\ArrayyIterator::class,
3636
bool $checkPropertiesInConstructor = true
3737
) {
38+
/** @phpstan-ignore return.type (generic static<TCreate> is not preserved through new static) */
3839
return new static(
3940
$data,
4041
$iteratorClass,

tests/CollectionStringyTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,14 @@ public function testFail()
4141
S::collection(['fòôbàř', 'lall', 1]);
4242
}
4343

44+
public function testCreateValidatesElementTypesByDefault()
45+
{
46+
$this->expectException(TypeError::class);
47+
$this->expectExceptionMessage('Invalid type: expected to be of type {Stringy\Stringy}, instead got value `1` with type {integer}.');
48+
49+
\Stringy\CollectionStringy::create([1]);
50+
}
51+
4452
public function testCollectionFunctionWithSingleString()
4553
{
4654
// A single (non-array) string must be wrapped and produce a one-element collection.

tests/StaticStringyTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ final class StaticStringyTest extends \PHPUnit\Framework\TestCase
1616
public function testBadMethodCall()
1717
{
1818
$this->expectException(\BadMethodCallException::class);
19+
$this->expectExceptionMessage('invalidMethod is not a valid method');
1920

2021
/** @noinspection PhpUndefinedMethodInspection */
2122
/** @noinspection PhpUnusedLocalVariableInspection */
@@ -56,6 +57,13 @@ public function testFullArgsInvocation()
5657
public function testArgumentNumbers()
5758
{
5859
$staticStringyClass = new ReflectionClass(S::class);
60+
$methodArgsProperty = $staticStringyClass->getProperty('methodArgs');
61+
$methodArgsProperty->setAccessible(true);
62+
// Reset the cache so this test always exercises __callStatic()'s argument counting.
63+
$methodArgsProperty->setValue(null, null);
64+
65+
S::slice('fòôbàř', 0, 3, 'UTF-8');
66+
5967
$stringyClass = new ReflectionClass(Stringy::class);
6068

6169
// getStaticPropertyValue can't access protected properties

tests/StringyTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2055,6 +2055,17 @@ public function testAppendStringy()
20552055
static::assertSame('abczzz123öäüdef', $result->toString());
20562056
}
20572057

2058+
public function testAppendStringyConcatenatesEveryArgument()
2059+
{
2060+
$result = S::create('abc')->appendStringy(
2061+
S::create('123'),
2062+
S::create('öäü'),
2063+
S::create('def')
2064+
);
2065+
2066+
static::assertSame('abc123öäüdef', $result->toString());
2067+
}
2068+
20582069
/**
20592070
* @dataProvider atProvider()
20602071
*
@@ -3897,6 +3908,18 @@ public function testWords()
38973908
}
38983909
}
38993910

3911+
public function testWordsKeepsEmptyValuesByDefault()
3912+
{
3913+
$words = S::create('foo oo oöäü#s')->words();
3914+
$result = [];
3915+
3916+
foreach ($words as $word) {
3917+
$result[] = $word->toString();
3918+
}
3919+
3920+
static::assertSame(['', 'foo', ' ', 'oo', ' ', 'oöäü', '#', 's', ''], $result);
3921+
}
3922+
39003923
/**
39013924
* @dataProvider splitProvider()
39023925
*
@@ -5493,6 +5516,20 @@ public function testItPreservesEncodingChunk()
54935516
}
54945517
}
54955518

5519+
public function testChunkUsesSingleCharacterLengthByDefault()
5520+
{
5521+
$chunks = S::create('foo')->chunk();
5522+
5523+
static::assertSame(['f', 'o', 'o'], \array_map('strval', $chunks));
5524+
}
5525+
5526+
public function testChunkCollectionUsesSingleCharacterLengthByDefault()
5527+
{
5528+
$chunks = S::create('foo')->chunkCollection();
5529+
5530+
static::assertSame(['f', 'o', 'o'], \array_map('strval', $chunks->toArray()));
5531+
}
5532+
54965533
public function testItCanBeExploded()
54975534
{
54985535
$string = new \Stringy\Stringy('john pinkerton');

0 commit comments

Comments
 (0)