Skip to content

Add SimpleCacheV3Test for PSR-16 v3 strict type hints (#121)#122

Open
GautamMKGarg wants to merge 6 commits into
php-cache:masterfrom
GautamMKGarg:master
Open

Add SimpleCacheV3Test for PSR-16 v3 strict type hints (#121)#122
GautamMKGarg wants to merge 6 commits into
php-cache:masterfrom
GautamMKGarg:master

Conversation

@GautamMKGarg
Copy link
Copy Markdown

Closes #121 (with the help of AI agents)

PSR-16 v3 (psr/simple-cache ^3.0) introduced strict PHP type hints:

  • string $key
  • iterable $keys
  • null|int|\DateInterval $ttl

This caused the existing SimpleCacheTest data providers to throw \TypeError
before implementation code ever ran, making many tests effectively broken for
v3 consumers.

What this PR does

  1. Adds SimpleCacheV3Test — a new subclass of SimpleCacheTest that:

    • Filters invalidKeys() and invalidArrayKeys() to only string invalid
      keys (non-string types are rejected by PHP before reaching the library)
    • Filters invalidTtl() to values that don't coerce to valid int/null in
      PHP weak mode
    • Introduces assertCacheExceptionOrTypeError() helper that accepts both
      \TypeError (PHP-level rejection) and InvalidArgumentException
      (library-level validation) as valid failures
    • Adds testBasicUsageWithLongKey64() — tests the PSR-16 mandated
      minimum
      key length of 64 characters
  2. Updates composer.json — adds psr/simple-cache: ^1.0 || ^2.0 || ^3.0
    to require-dev so the test suite can be developed against any version

  3. Updates README.md — documents SimpleCacheV3Test usage

Backward compatibility

SimpleCacheTest is completely untouched. Existing v1/v2 consumers continue
using it without any changes. V3 consumers switch to SimpleCacheV3Test.

Tested against

  • Verified with gautammkgarg/psr-for-wordpress
    (Packagist) —
    a real PSR-16 v3 WordPress bridge implementation (transients + object cache
    adapters, 466 tests, 2251 assertions, all passing)

@stof
Copy link
Copy Markdown
Contributor

stof commented May 20, 2026

I think we should have a single test class, to make it easier for projects supporting multiple versions of psr/cache in parallel.
If some data providers need to provide different values depending on the psr/cache version, you could use InstalledVersions from the composer-runtime-api for that. However, I'm not even sure this should be the case. You could have psr/cache 2+ installed while not having native types on parameters in the implementation (which is the way to support version 1 and 2 at the same time). Testing inputs that violate the contract should probably be moved to separate data providers used by tests using assertCacheExceptionOrTypeError

@GautamMKGarg
Copy link
Copy Markdown
Author

@stof Thank you for the detailed feedback and sorry for the delay in response — this architecture is much cleaner than the subclass approach.

I have updated the tests with some help from the AI tools, Here's what's been refactored:

  • Removed SimpleCacheV3Test entirely — SimpleCacheTest is now the single class for all versions.
  • Added runtime version detection via Composer\InstalledVersions::getVersion('psr/simple-cache') (cached per process).
  • Added declare(strict_types=1) to the test file — this is necessary so that v2/v3 contract violations actually throw TypeError before reaching the library. Without it, PHP would silently coerce non-string keys (e.g., true"1") and the type-violation tests would pass with no error thrown.
  • Split data providers:
    • invalidKeys(), invalidArrayKeys(), invalidTtl() — return only syntax-invalid values on v2/v3 (survive PHP type hints → InvalidArgumentException)
    • New *TypeViolation() providers — return non-string keys / invalid TTL types on v2/v3, empty arrays on v1
  • Added assertCacheExceptionOrTypeError() helper accepting both TypeError and InvalidArgumentException.
  • Added testBasicUsageWithLongKey64 for the PSR-16 mandated 64-char minimum.
  • NoIterable tests conditionally use assertCacheExceptionOrTypeError on v2/v3.

Backward compatibility with v1 is preserved:

  • All original data providers return the same values on v1.
  • declare(strict_types=1) has no effect on v1 — since v1 interfaces have no parameter type hints, there's nothing for PHP to enforce.
  • The 9 new *TypeViolation tests auto-skip on v1 (empty data providers — standard PHPUnit behavior, no configuration needed).
  • Tested against cache/array-adapter — all 359 tests pass, 0 failures.

Would appreciate your review when you have time.

Copy link
Copy Markdown
Contributor

@stof stof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@GautamMKGarg checking the version of the interface package to decide between TypeError or InvalidArgumentException is the wrong approach. When writing an implementation supporting 2 versions of the interface, the types can differ between the interface and the implementation (respecting variance rules), and PHP will enforce strict types based on the implementation, not based on the interface.
I think you should always use assertCacheExceptionOrTypeError, without the switch based on self::isPsr16V1() to account for that.

And this PR should probably also cover the PSR-6 tests, as we have the same kind of stricter types for PSR-6 than for PSR-16.

Comment thread src/SimpleCacheTest.php Outdated
@GautamMKGarg
Copy link
Copy Markdown
Author

@stof Thanks for more information. I have more remaining changes with the help of AI tools. This PR is ready for another review. Changes made:

SimpleCacheTest: Removed isPsr16V1(), restored *TypeViolation providers as separate data providers, syntax tests assert InvalidArgumentException, type-violation tests assert TypeError or InvalidArgumentException, TTL tests use assertCacheExceptionOrTypeError.

CachePoolTest: Added declare(strict_types=1) and assertCacheExceptionOrTypeError(), updated testGetItemInvalidKeys / testHasItemInvalidKeys / testDeleteItemInvalidKeys, fixed DateTime::createFromFormat casts for strict mode.

Questions:
(1) Should testBasicUsageWithLongKey64 stay, move to a separate PR, or be removed?
(2) Would you like a shared trait/base class for assertCacheExceptionOrTypeError to avoid duplication between PSR-6 and PSR-16?

@GautamMKGarg GautamMKGarg requested a review from stof June 2, 2026 04:02
@stof
Copy link
Copy Markdown
Contributor

stof commented Jun 2, 2026

I suggest submitting testBasicUsageWithLongKey64 in a separate PR instead, as it is a separate topic.

Removed test for PSR-16 minimum key length of 64 characters.
Moving it in a seperate PR as suggested by @stof
@GautamMKGarg
Copy link
Copy Markdown
Author

Thanks @stof for your suggestion. I have removed testBasicUsageWithLongKey64 from this PR. Is everything else fine? is the PR ready for merge?

Copy link
Copy Markdown
Contributor

@stof stof left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me, but it will require someone with write access to the repo to allow workflow runs and to perform a review and merge. I don't have access to this repo.

@GautamMKGarg
Copy link
Copy Markdown
Author

GautamMKGarg commented Jun 2, 2026

Hello @aequasi / @Nyholm

Kindly check this when you are available.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PHP FIG SimpleCache 2021 updates

2 participants