Repository navigation
Conversation
|
@NickSdot could you target to 0.20.x branch? Also fix phpstan and re-run rector and cs, eg: composer phpstan
composer rector
composer cs-fix |
35c7e1f to
2850343
Compare
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
2850343 to
725bb3d
Compare
|
@NickSdot could you add more test to make 100% test coverage? Use e2e test on tests/Analyser/AnalyserTest.php may help to demonstrate the use case. |
|
@NickSdot needs another 3% coverage test: |
|
@NickSdot tried locally, needs another 1% to cover 100% ➜ structarmed git:(feat/cache-fingerprinting) vendor/bin/phpunit --coverage-text
Analyzing [============================] 100% 293/293
StructArmed dev-main — Architecture Enforcement
=================================================
✅ No violations found. (0.51s)
PHPUnit 11.5.57 by Sebastian Bergmann and contributors.
Runtime: PHP 8.4.25 with Xdebug 3.5.0
Configuration: /Users/samsonasik/www/boundwize/structarmed/phpunit.xml
............................................................. 61 / 1778 ( 3%)
............................................................. 122 / 1778 ( 6%)
............................................................. 183 / 1778 ( 10%)
............................................................. 244 / 1778 ( 13%)
............................................................. 305 / 1778 ( 17%)
............................................................. 366 / 1778 ( 20%)
............................................................. 427 / 1778 ( 24%)
............................................................. 488 / 1778 ( 27%)
............................................................. 549 / 1778 ( 30%)
............................................................. 610 / 1778 ( 34%)
............................................................. 671 / 1778 ( 37%)
............................................................. 732 / 1778 ( 41%)
............................................................. 793 / 1778 ( 44%)
............................................................. 854 / 1778 ( 48%)
............................................................. 915 / 1778 ( 51%)
............................................................. 976 / 1778 ( 54%)
............................................................. 1037 / 1778 ( 58%)
............................................................. 1098 / 1778 ( 61%)
............................................................. 1159 / 1778 ( 65%)
............................................................. 1220 / 1778 ( 68%)
............................................................. 1281 / 1778 ( 72%)
............................................................. 1342 / 1778 ( 75%)
............................................................. 1403 / 1778 ( 78%)
............................................................. 1464 / 1778 ( 82%)
............................................................. 1525 / 1778 ( 85%)
............................................................. 1586 / 1778 ( 89%)
............................................................. 1647 / 1778 ( 92%)
............................................................. 1708 / 1778 ( 96%)
............................................................. 1769 / 1778 ( 99%)
......... 1778 / 1778 (100%)
=========
Pyrameter
=========
Shape: Healthy Pyramid
Result: Passed ✓
▲ E2E -
▄▄▄▄▄ Functional -
▄▄▄▄▄▄▄▄▄ Integration ✓
▄▄▄▄▄▄▄▄▄▄▄▄▄ Unit ✓
+=============+=======+========+============+
| KIND | TESTS | ACTUAL | TARGET |
+=============+=======+========+============+
| Unit | 949 | 53.4% | >= 50.0% ✓ |
+-------------+-------+--------+------------+
| Integration | 829 | 46.6% | <= 50.0% ✓ |
+-------------+-------+--------+------------+
| Functional | 0 | 0.0% | No target |
+-------------+-------+--------+------------+
| E2E | 0 | 0.0% | No target |
+-------------+-------+--------+------------+
Total: 1778 tests
Your test pyramid target passed.
Time: 00:46.113, Memory: 70.00 MB
OK (1778 tests, 4595 assertions)
Code Coverage Report:
2026-10-29 13:36:33
Summary:
Classes: 99.30% (141/142)
Methods: 99.86% (693/694)
Lines: 99.95% (6344/6347)
Boundwize\StructArmed\Analyser\Analyser
Methods: 100.00% (33/33) Lines: 100.00% (738/738)
Boundwize\StructArmed\Analyser\AnalyserOptions
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 8/ 8)
Boundwize\StructArmed\Analyser\AnalysisNodeCollector
Methods: 100.00% (56/56) Lines: 100.00% (676/676)
Boundwize\StructArmed\Analyser\AnalysisNodeExtractor
Methods: 100.00% ( 4/ 4) Lines: 100.00% (104/104)
Boundwize\StructArmed\Analyser\AnonymousClassNode
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 2/ 2)
Boundwize\StructArmed\Analyser\AnonymousFunctionNode
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 3/ 3)
Boundwize\StructArmed\Analyser\ClassLikeAnalysis
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 1/ 1)
Boundwize\StructArmed\Analyser\ClassNode
Methods: 100.00% (13/13) Lines: 100.00% ( 38/ 38)
Boundwize\StructArmed\Analyser\ConstantNode
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 1/ 1)
Boundwize\StructArmed\Analyser\EnumCaseNode
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 2/ 2)
Boundwize\StructArmed\Analyser\ExtractionResult
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 10/ 10)
Boundwize\StructArmed\Analyser\FileAnalysis
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 1/ 1)
Boundwize\StructArmed\Analyser\FileAnalysisProvider
Methods: 100.00% (27/27) Lines: 100.00% (243/243)
Boundwize\StructArmed\Analyser\FunctionLikeAnalysis
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 1/ 1)
Boundwize\StructArmed\Analyser\FunctionNode
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 7/ 7)
Boundwize\StructArmed\Analyser\MemberQueryTrait
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 4/ 4)
Boundwize\StructArmed\Analyser\MethodNode
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 4/ 4)
Boundwize\StructArmed\Analyser\NameQueryTrait
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 2/ 2)
Boundwize\StructArmed\Analyser\NodeQueryTrait
Methods: 100.00% ( 7/ 7) Lines: 100.00% ( 26/ 26)
Boundwize\StructArmed\Analyser\Parallel\AnalysisNodeWorker
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 48/ 48)
Boundwize\StructArmed\Analyser\Parallel\ParallelAnalysisNodeExtractor
Methods: 100.00% ( 6/ 6) Lines: 100.00% (185/185)
Boundwize\StructArmed\Analyser\Parallel\WorkerProgressHandler
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 4/ 4)
Boundwize\StructArmed\Analyser\PropertyNode
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 1/ 1)
Boundwize\StructArmed\Analyser\PropertyUnserializeTrait
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 2/ 2)
Boundwize\StructArmed\Analyser\RecursiveParentsTrait
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 11/ 11)
Boundwize\StructArmed\Architecture
Methods: 100.00% (33/33) Lines: 100.00% ( 99/ 99)
Boundwize\StructArmed\Baseline\Baseline
Methods: 100.00% ( 9/ 9) Lines: 100.00% (111/111)
Boundwize\StructArmed\Baseline\BaselineFilter
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 7/ 7)
Boundwize\StructArmed\Cache\AnalysisCacheMetadataFactory
Methods: 100.00% ( 9/ 9) Lines: 100.00% ( 36/ 36)
Boundwize\StructArmed\Cache\AnalysisResultCache
Methods: 100.00% (45/45) Lines: 100.00% (785/785)
Boundwize\StructArmed\Cache\CachePathFactory
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 4/ 4)
Boundwize\StructArmed\Cache\ConfigurationFingerprint
Methods: 83.33% ( 5/ 6) Lines: 97.00% ( 97/100)
Boundwize\StructArmed\Cache\FileHashProvider
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 10/ 10)
Boundwize\StructArmed\Cli\AnalyseCommand
Methods: 100.00% ( 7/ 7) Lines: 100.00% (215/215)
Boundwize\StructArmed\Cli\ClearCacheCommand
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 28/ 28)
Boundwize\StructArmed\Cli\ColorSupport
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 21/ 21)
Boundwize\StructArmed\Cli\InitCommand
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 50/ 50)
Boundwize\StructArmed\Cli\StructArmedApplication
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 26/ 26)
Boundwize\StructArmed\Composer\ComposerJsonProvider
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 14/ 14)
Boundwize\StructArmed\Composer\Psr4PathResolver
Methods: 100.00% ( 8/ 8) Lines: 100.00% ( 49/ 49)
Boundwize\StructArmed\Config\ConfigLoader
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 26/ 26)
Boundwize\StructArmed\File\PhpFileCollector
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 17/ 17)
Boundwize\StructArmed\File\SkipPathMatcher
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 43/ 43)
Boundwize\StructArmed\LayerResolver\ChainLayerResolver
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 26/ 26)
Boundwize\StructArmed\LayerResolver\Resolvers\ClassNameRegexLayerResolver
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 22/ 22)
Boundwize\StructArmed\LayerResolver\Resolvers\NamespaceLayerResolver
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 40/ 40)
Boundwize\StructArmed\PHPUnit\StructArmedExtension
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 60/ 60)
Boundwize\StructArmed\Preset\Preset
Methods: 100.00% ( 9/ 9) Lines: 100.00% ( 34/ 34)
Boundwize\StructArmed\Preset\Presets\CodeQualityPreset
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 11/ 11)
Boundwize\StructArmed\Preset\Presets\DddPreset
Methods: 100.00% (10/10) Lines: 100.00% (152/152)
Boundwize\StructArmed\Preset\Presets\MvcPreset
Methods: 100.00% (11/11) Lines: 100.00% (206/206)
Boundwize\StructArmed\Preset\Presets\PerPreset
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 23/ 23)
Boundwize\StructArmed\Preset\Presets\Psr12Preset
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 23/ 23)
Boundwize\StructArmed\Preset\Presets\Psr15Preset
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 35/ 35)
Boundwize\StructArmed\Preset\Presets\Psr1Preset
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 20/ 20)
Boundwize\StructArmed\Preset\Presets\Psr4Preset
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 15/ 15)
Boundwize\StructArmed\Preset\Presets\ResolvesSourceLayerNameTrait
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 14/ 14)
Boundwize\StructArmed\Preset\Presets\YagniPreset
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 23/ 23)
Boundwize\StructArmed\Progress\ConsoleProgressBar
Methods: 100.00% ( 6/ 6) Lines: 100.00% ( 54/ 54)
Boundwize\StructArmed\Report\Reports\ConsoleReport
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 33/ 33)
Boundwize\StructArmed\Report\Reports\GithubReport
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 14/ 14)
Boundwize\StructArmed\Report\Reports\JsonReport
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 6/ 6)
Boundwize\StructArmed\Rule\AbstractLayerAwareRule
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 2/ 2)
Boundwize\StructArmed\Rule\Fixer\JsonRecast\AbstractJsonRecastFixableRule
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 15/ 15)
Boundwize\StructArmed\Rule\Fixer\JsonRecast\JsonRecastFixerProcessor
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 17/ 17)
Boundwize\StructArmed\Rule\Fixer\JsonRecast\ObjectItemNode\RemoveMissingPsr4PathVisitor
Methods: 100.00% (14/14) Lines: 100.00% ( 46/ 46)
Boundwize\StructArmed\Rule\Fixer\PhpParser\AbstractPhpParserFixableRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 17/ 17)
Boundwize\StructArmed\Rule\Fixer\PhpParser\AbstractTokenAwareVisitor
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 1/ 1)
Boundwize\StructArmed\Rule\Fixer\PhpParser\ClassConst\AddPublicConstantVisibilityVisitor
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 17/ 17)
Boundwize\StructArmed\Rule\Fixer\PhpParser\ClassConst\ChangeProtectedConstantToPrivateVisitor
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 18/ 18)
Boundwize\StructArmed\Rule\Fixer\PhpParser\ClassLike\RemoveClassLikeVisitor
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 8/ 8)
Boundwize\StructArmed\Rule\Fixer\PhpParser\ClassMethod\AddPublicMethodVisibilityVisitor
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 12/ 12)
Boundwize\StructArmed\Rule\Fixer\PhpParser\ClassMethod\ChangeProtectedMethodToPrivateVisitor
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 13/ 13)
Boundwize\StructArmed\Rule\Fixer\PhpParser\Class_\AddAbstractClassVisitor
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 9/ 9)
Boundwize\StructArmed\Rule\Fixer\PhpParser\Class_\AddFinalClassVisitor
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 9/ 9)
Boundwize\StructArmed\Rule\Fixer\PhpParser\Class_\RemoveAnonymousClassParenthesesVisitor
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 12/ 12)
Boundwize\StructArmed\Rule\Fixer\PhpParser\ConstFetch\LowercaseKeywordConstantVisitor
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 15/ 15)
Boundwize\StructArmed\Rule\Fixer\PhpParser\FunctionLike\AddStaticAnonymousFunctionVisitor
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 31/ 31)
Boundwize\StructArmed\Rule\Fixer\PhpParser\Function_\RemoveFunctionVisitor
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 29/ 29)
Boundwize\StructArmed\Rule\Fixer\PhpParser\PhpParserFixerProcessor
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 44/ 44)
Boundwize\StructArmed\Rule\Fixer\PhpParser\Property\AddPublicPropertyVisibilityVisitor
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 25/ 25)
Boundwize\StructArmed\Rule\Fixer\PhpParser\Scalar\AddNumericLiteralSeparatorsVisitor
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 17/ 17)
Boundwize\StructArmed\Rule\RuleViolation
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 29/ 29)
Boundwize\StructArmed\Rule\RuleViolationCollection
Methods: 100.00% ( 9/ 9) Lines: 100.00% ( 21/ 21)
Boundwize\StructArmed\Rule\Rules\Class_\AnonymousClassMayNotHaveEmptyParenthesesRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 15/ 15)
Boundwize\StructArmed\Rule\Rules\Class_\ClassConstantNameMustBeUpperCaseRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 21/ 21)
Boundwize\StructArmed\Rule\Rules\Class_\ClassImplementingInterfaceMustHaveSuffixRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 18/ 18)
Boundwize\StructArmed\Rule\Rules\Class_\ClassNameMustBeStudlyCapsRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 11/ 11)
Boundwize\StructArmed\Rule\Rules\Class_\ClassNameMustHaveSuffixRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 16/ 16)
Boundwize\StructArmed\Rule\Rules\Class_\ClassNameMustNotHavePrefixRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 16/ 16)
Boundwize\StructArmed\Rule\Rules\Class_\EnumCaseNameMustBePascalCaseRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 20/ 20)
Boundwize\StructArmed\Rule\Rules\Class_\EnumConstantMayNotBeProtectedRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 26/ 26)
Boundwize\StructArmed\Rule\Rules\Class_\EnumMethodMayNotBeProtectedRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 26/ 26)
Boundwize\StructArmed\Rule\Rules\Class_\ExtendedClassMustBeAbstractOrInstantiatedRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 27/ 27)
Boundwize\StructArmed\Rule\Rules\Class_\MaxDependencyCountRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 18/ 18)
Boundwize\StructArmed\Rule\Rules\Class_\MayNotExtendClassRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 11/ 11)
Boundwize\StructArmed\Rule\Rules\Class_\MayNotImplementInterfaceRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 18/ 18)
Boundwize\StructArmed\Rule\Rules\Class_\MustBeFinalRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 23/ 23)
Boundwize\StructArmed\Rule\Rules\Class_\MustBeInterfaceRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 19/ 19)
Boundwize\StructArmed\Rule\Rules\Class_\MustBeUsedAbstractClassRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 24/ 24)
Boundwize\StructArmed\Rule\Rules\Class_\MustBeUsedInterfaceRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 25/ 25)
Boundwize\StructArmed\Rule\Rules\Class_\MustBeUsedTraitRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 22/ 22)
Boundwize\StructArmed\Rule\Rules\Class_\MustDeclareConstantVisibilityRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 25/ 25)
Boundwize\StructArmed\Rule\Rules\Class_\MustDeclareMethodVisibilityRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 25/ 25)
Boundwize\StructArmed\Rule\Rules\Class_\MustDeclarePropertyVisibilityRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 25/ 25)
Boundwize\StructArmed\Rule\Rules\Class_\MustImplementInterfaceRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 19/ 19)
Boundwize\StructArmed\Rule\Rules\Class_\NamingConventionRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 23/ 23)
Boundwize\StructArmed\Rule\Rules\Composer\Psr4DirectoryExistsRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 26/ 26)
Boundwize\StructArmed\Rule\Rules\Composer\Psr4EmptyNamespacePrefixRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 32/ 32)
Boundwize\StructArmed\Rule\Rules\Composer\Psr4NamespaceRule
Methods: 100.00% ( 7/ 7) Lines: 100.00% ( 60/ 60)
Boundwize\StructArmed\Rule\Rules\Composer\Psr4RootPathRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 41/ 41)
Boundwize\StructArmed\Rule\Rules\Composer\Psr4SourcePathsRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 41/ 41)
Boundwize\StructArmed\Rule\Rules\File\LargeNumericLiteralMustUseSeparatorRule
Methods: 100.00% ( 8/ 8) Lines: 100.00% ( 50/ 50)
Boundwize\StructArmed\Rule\Rules\File\MustUseLowercaseKeywordConstantRule
Methods: 100.00% ( 6/ 6) Lines: 100.00% ( 32/ 32)
Boundwize\StructArmed\Rule\Rules\File\PhpFileFinder
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 37/ 37)
Boundwize\StructArmed\Rule\Rules\File\Psr1PhpTagsRule
Methods: 100.00% (10/10) Lines: 100.00% ( 74/ 74)
Boundwize\StructArmed\Rule\Rules\File\Psr1SymbolsOrSideEffectsRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 32/ 32)
Boundwize\StructArmed\Rule\Rules\File\Psr1Utf8WithoutBomRule
Methods: 100.00% ( 6/ 6) Lines: 100.00% ( 31/ 31)
Boundwize\StructArmed\Rule\Rules\File\Psr1ValidUtf8Rule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 25/ 25)
Boundwize\StructArmed\Rule\Rules\Function_\MustBeStaticAnonymousFunctionRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 18/ 18)
Boundwize\StructArmed\Rule\Rules\Function_\MustBeUsedFunctionRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 21/ 21)
Boundwize\StructArmed\Rule\Rules\Function_\MustHaveReturnTypeFunctionRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 15/ 15)
Boundwize\StructArmed\Rule\Rules\Layer\MayNotDependOnRule
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 29/ 29)
Boundwize\StructArmed\Rule\Rules\Method\MaxCyclomaticComplexityRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 20/ 20)
Boundwize\StructArmed\Rule\Rules\Method\MaxMethodLengthRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 20/ 20)
Boundwize\StructArmed\Rule\Rules\Method\MethodNameMustBeCamelCaseRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 22/ 22)
Boundwize\StructArmed\Rule\Rules\Method\MustHaveReturnTypeRule
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 26/ 26)
Boundwize\StructArmed\Rule\Rules\Usage\MayNotCallFunctionRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 16/ 16)
Boundwize\StructArmed\Rule\Rules\Usage\MayNotUseClassRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 20/ 20)
Boundwize\StructArmed\Rule\Rules\Usage\MayNotUseConstantRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 16/ 16)
Boundwize\StructArmed\Rule\Rules\Usage\MayNotUseLanguageConstructRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 16/ 16)
Boundwize\StructArmed\Rule\Rules\Usage\MayNotUseNamespaceRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 20/ 20)
Boundwize\StructArmed\Rule\Rules\Usage\MayNotUseSuperglobalsRule
Methods: 100.00% ( 3/ 3) Lines: 100.00% ( 16/ 16)
Boundwize\StructArmed\Util\InlineHtmlOpeningTagMatcher
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 8/ 8)
Boundwize\StructArmed\Util\Path
Methods: 100.00% ( 5/ 5) Lines: 100.00% ( 49/ 49)
Boundwize\StructArmed\Util\PhpParser\AnonymousClassParentheses
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 29/ 29)
Boundwize\StructArmed\Util\PhpParser\ObjectBoundAnonymousFunction
Methods: 100.00% ( 4/ 4) Lines: 100.00% ( 32/ 32)
Boundwize\StructArmed\Util\PhpParser\ProtectedToPrivateFlags
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 3/ 3)
Boundwize\StructArmed\Util\PhpParser\UnconditionallyDeclaredFunctions
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 8/ 8)
Boundwize\StructArmed\Util\PhpParser\VisibilityFlagChecker
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 1/ 1)
Boundwize\StructArmed\Util\SourceLayerName
Methods: 100.00% ( 1/ 1) Lines: 100.00% ( 2/ 2)
Boundwize\StructArmed\Version
Methods: 100.00% ( 2/ 2) Lines: 100.00% ( 5/ 5) |
There was a problem hiding this comment.
🟡 Changes recommended
Configuration fingerprints omit stored object options, nested rule configuration, and closure or anonymous-rule source changes, allowing stale cached results to be reused after configuration changes.
2 open issues
What changed in this PR
Extends cache identity with the evaluated Architecture, allowing configuration changes from required PHP files to invalidate StructArmed’s analysis caches.
Changes:
- Combines architecture fingerprints with the root configuration file’s content hash.
- Uses the combined identity in CLI and PHPUnit caches and bumps cache versions.
- Adds unit and cross-process tests for fingerprint stability and configuration-driven invalidation.
| File | Description |
|---|---|
tests/Fixtures/Cache/RuleSettingsGroup.php |
Provides nested readonly settings for graph tests. |
tests/Fixtures/Cache/RuleSettings.php |
Provides readonly options, bound callbacks, and custom serialization. |
tests/Fixtures/Cache/RulePolicy.php |
Provides enum settings for identity tests. |
tests/Fixtures/Cache/CyclicRuleSettings.php |
Provides self-referencing settings for cycle tests. |
tests/Cache/ConfigurationFingerprintTest.php |
Tests deterministic identities, configuration values, and runtime-state exclusion. |
tests/Cache/ConfigurationCacheTest.php |
Tests cache invalidation across CLI modes and the PHPUnit extension. |
tests/Cache/AnalysisResultCacheTest.php |
Updates expectations for metadata versions and supplied configuration hashes. |
tests/Cache/AnalysisCacheMetadataFactoryTest.php |
Tests combined architecture and root-file hashing. |
src/PHPUnit/StructArmedExtension.php |
Uses the combined configuration identity for analysis caches. |
src/Cli/AnalyseCommand.php |
Shares the combined identity across cache operations. |
src/Cache/ConfigurationFingerprint.php |
Adds fingerprinting of evaluated architecture and rule settings. |
src/Cache/AnalysisResultCache.php |
Bumps the cache format to invalidate older entries. |
src/Cache/AnalysisCacheMetadataFactory.php |
Combines configuration hashes and includes them in versioned metadata. |
Review effort: Max
| $function->getFileName(), | ||
| $function->getStartLine(), | ||
| $function->getEndLine(), |
There was a problem hiding this comment.
Known limitation. Codex recommended the same, I decided against. I'd not bypass cache by default. Given that currently everything remains cached this is already improving things. I'd leave it as is and let you, @samsonasik, decide whether custom rules at a later point might should be able to manually opt out form caching in some way (property, interface or the like).
| return $class->isReadOnly() | ||
| ? $this->properties($value, $ancestors, $depth) | ||
| : ['opaque', $this->classIdentity($class)]; |
CI collects PHP 8.2 coverage only , tests alone cannot cover the PHP 8.4 paths here. If you want this at 100% we must add machinery for optional reflection, and version switches, just to make coverage happy. Worth it? |
|
@NickSdot I see, I am thinking that this return Architecture::define()
->import(__DIR__ . '/module/Foo/structarmed.php')
->import(__DIR__ . '/module/Bar/structarmed.php');The imported config can be: // module/Foo/structarmed.php
return static function (Architecture $architecture): void {
$architecture
->layer('Foo', 'module/Foo/src/')
->rule('foo-rule', new FooRule());
};so proper imported files can be checked on /** @var list<string> */
private array $importedFiles = [];
public function import(string $file): self
{
$configure = require $file;
if (! is_callable($configure)) {
throw new InvalidArgumentException(
'Imported configuration must return a callable.'
);
}
$configure($this);
$this->importedFiles[] = realpath($file) ?: $file;
return $this;
}
/** @return list<string> */
public function getImportedFiles(): array
{
return $this->importedFiles;
} |
|
@NickSdot I created alternative PR for it: should be simpler to maintain ;) |
|
@NickSdot Thank you for the effort on it. I am closing it in favor of as I am thinking that will be easier to maintain :) |
Sure, if you rip our all the helpful functionality then it's simpler. ;) Closing this in the middle of everything is quite something. Never mind, will fork -- thanks for considering! |
|
I am sorry about that :). This PR solution require continuation look as it verify everything in the Architecture object and the rule interfaces, which in the future is not ideal imo. |

Hey!
What
Cache invalidation currently relies on the config file being edited. That is missing changes to config from other inputs. This PR instead fingerprints the evaluated Architecture.
structarmed.phpcan require layer definitions from another PHP file. Changes in required files leavestructarmed.phpand hence cache identity unchanged. This means StructArmed can reuse caches in situations where the config had external changes.B/C: since this changes cache identity, existing caches will miss on first run after updating.
Why
You might recall from our Twitter interaction that I am working in a modular monolith -- think of it as many Composer packages in one repo; each with its own rules. The config API doesn't really scale with that, so I've built a wrapper on top of StructArmed. Although I was able to work around the issue I think it's good to fix it in StructArmed itself.
* implementation by Codex