Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
e9d8e17
Add requirement to always use the current version of AGENTS.md
k2gl Jan 21, 2026
d06703b
Add logical grouping with regions to StringAssertions trait
k2gl Jan 21, 2026
a3830aa
Strengthen PHPDoc rule: Example usage MUST be placed before @param an…
k2gl Jan 21, 2026
8ad3689
Add rules: refresh/re-read AGENTS.md before changes, and checkout new…
k2gl Jan 21, 2026
4e0467c
Add rule: do not push automatically, only after explicit user request
k2gl Jan 21, 2026
98c15a3
Fix Example usage order in TypeCheckingAssertions PHPDoc to comply wi…
k2gl Jan 21, 2026
e77be15
Fix Example usage order in NumericAssertions PHPDoc to comply with AG…
k2gl Jan 21, 2026
c594e81
Fix Example usage order in ArrayAssertions PHPDoc to comply with AGEN…
k2gl Jan 21, 2026
efe0132
Add remaining trait files and update configs for comprehensive improv…
k2gl Jan 21, 2026
a9146b4
Add isNotEmptyArray method with tests and documentation
k2gl Jan 21, 2026
00230ea
Update @return descriptions for all methods to 'Enables fluent chaini…
k2gl Jan 21, 2026
7d11afb
Update @return descriptions across all traits for consistency
k2gl Jan 21, 2026
25ddfef
Fix ArgumentTypeCoercion warnings in startsWith and endsWith
k2gl Jan 21, 2026
ec9868b
Update StringAssertions method signatures to use non-empty-string types
k2gl Jan 21, 2026
af0c774
Fix PHPStan errors in StringAssertions: change empty string checks to…
k2gl Jan 21, 2026
c6c918f
Deep analysis and fixes for StringAssertions: corrected PHPDoc @param…
k2gl Jan 21, 2026
05e4986
Fix @return PHPDoc in all traits: change self|FluentAssertions to self
k2gl Jan 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,33 @@ This file outlines the requirements and best practices for adding new assertion

## General Requirements

- **Branching and Commits**: It is forbidden to commit directly to the `main` branch. All changes must be added via pull request from a feature branch.
- **Version Compliance**: Always use the most current version of AGENTS.md and do not rely on cached or outdated copies. Refresh and re-read AGENTS.md before every change to ensure compliance with the latest requirements.
- **Branching and Commits**: It is forbidden to commit directly to the `main` branch. All changes must be added via pull request from a feature branch. If the current branch is `main`, MUST checkout to a new branch before changing any files. Do not push changes automatically—only push after explicit user request.
- **Method Signature**: All new methods must be public, accept an optional `$message` parameter (string, default empty), and return `self` to enable fluent chaining.
- **Type Safety**: Specify strict types for parameters where applicable (e.g., `int|float` for numeric comparisons). Avoid `mixed` unless necessary.
- **PHPUnit Integration**: Use appropriate PHPUnit assertion methods (e.g., `Assert::assertLessThan`) without named parameters for compatibility.
- **Fluent Design**: Ensure the method integrates seamlessly with the fluent interface.

## Code Organization

- **Trait-Based Structure**: Methods are organized into separate traits in `src/Traits/` for better maintainability.
- `ComparisonAndEqualityAssertions`: Basic equality checks.
- `BooleanAssertions`: True/false assertions.
- `NullAssertions`: Null checks.
- `NumericAssertions`: Numeric comparisons (e.g., isPositive, isBetween).
- `StringAssertions`: String operations (e.g., startsWith, hasLength).
- `ArrayAssertions`: Array checks (e.g., contains, hasSize).
- `TypeCheckingAssertions`: Type validation (e.g., isInt, instanceOf, hasProperty).
- `SpecialAssertions`: Specialized checks (e.g., ULID).
- Traits are imported into `FluentAssertions` class using `use` statements.
- Place new methods in the appropriate trait based on functionality.

## Documentation

- **PHPDoc**: Provide comprehensive PHPDoc with:
- Brief description of what the assertion does.
- Detailed explanation of the method's behavior.
- Example usage in the docblock (placed before @param and @return).
- Example usage in the docblock (MUST always be placed before @param and @return sections—never violate this order).
- `@param` tags for each parameter (including $message).
- `@return self` tag for fluent chaining.
- **README.md**: Update the usage section with an example of the new method in the fluent chain.
Expand Down
79 changes: 39 additions & 40 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,46 +33,45 @@ $user->setPhone(
self::assertSame(expected: $phoneAfter, actual: $user->getPhone());
self::assertNotSame(expected: $phoneBefore, actual: $user->getPhone());

// fluent assertions
fact($user->getPhone())
->is($phoneAfter)
->equals($phoneAfter)
->not($phoneBefore)
->true()
->notTrue()
->false()
->notFalse()
->null()
->notNull()
->matchesRegularExpression('#^\d+$#')
->notMatchesRegularExpression('#^\D+$#')
->containsString('alpha')
->notContainsString('alpha')
->containsStringIgnoringCase('beta')
->notContainsStringIgnoringCase('beta')
->count(5)
->notCount(5)
->arrayHasKey('echo')
->arrayNotHasKey('echo')
->instanceOf(UserFactory::class)
->notInstanceOf(UserFactory::class)
->ulid() // Universally Unique Lexicographically Sortable Identifier https://github.com/ulid/spec
->isLowerThan(100)
->isGreaterThan(50)
->isPositive()
->isNegative()
->isZero()
->isBetween(1, 10)
->startsWith('prefix')
->endsWith('suffix')
->hasLength(5)
->contains('value')
->doesNotContain('value')
->hasSize(3)
->isEmptyArray()
->isEmptyString()
->isInt()
->isString()
### Comparison and Equality Methods
```php
fact(42)->is(42)->equals(42)->not(43);
```

### Boolean Methods
```php
fact(true)->true()->notFalse();
```

### Null Methods
```php
fact(null)->null()->notNull();
```

### Numeric Methods
```php
fact(5)->isLowerThan(10)->isGreaterThan(0)->isPositive()->isNegative()->isZero()->isBetween(1, 10);
```

### String Methods
```php
fact('hello world')->matchesRegularExpression('/\w+/')->startsWith('hello')->endsWith('world')->hasLength(11)->isEmptyString();
```

### Array Methods
```php
fact([1, 2, 3])->count(3)->contains(2)->doesNotContain(4)->hasSize(3)->isEmptyArray()->isNotEmptyArray();
```

### Type Checking Methods
```php
fact(42)->isInt()->isString()->instanceOf(int::class)->hasProperty('name')->hasMethod('doSomething');
```

### Special Methods
```php
fact('01ARZ3NDEKTSV4RRFFQ69G5FAV')->ulid();
```
...
;

Expand Down
24 changes: 18 additions & 6 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,22 @@
"src/aliases.php"
]
},
"autoload-dev": {
"psr-4": {
"K2gl\\PHPUnitFluentAssertions\\Tests\\": "tests/"
}
},
"minimum-stability": "stable"
"autoload-dev": {
"psr-4": {
"K2gl\\PHPUnitFluentAssertions\\Tests\\": "tests/"
}
},
"minimum-stability": "stable",
"scripts": {
"analyze": [
"@phpstan",
"@psalm"
],
"phpstan": "./vendor/bin/phpstan analyse",
"psalm": "./vendor/bin/psalm.phar --config=psalm.xml"
},
"require-dev": {
"psalm/phar": "^6.14",
"phpstan/phpstan": "^2.1"
}
}
6 changes: 6 additions & 0 deletions phpstan.neon
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
parameters:
level: 5
paths:
- src
excludePaths:
- vendor
21 changes: 21 additions & 0 deletions psalm.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<psalm
errorLevel="3"
resolveFromConfigFile="true"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="https://getpsalm.org/schema/config"
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
>
<projectFiles>
<directory name="src" />
<ignoreFiles>
<directory name="vendor" />
</ignoreFiles>
</projectFiles>

<issueHandlers>
<LessSpecificReturnType errorLevel="info" />
<MoreSpecificReturnType errorLevel="info" />
<LessSpecificReturnStatement errorLevel="info" />
</issueHandlers>
</psalm>
Loading