From f06be7993ccd8dfc49ce5d3a05d3f0ff694bcbc0 Mon Sep 17 00:00:00 2001 From: Jasper Smet Date: Wed, 21 Oct 2026 20:25:57 +0200 Subject: [PATCH] test: cover native CakePHP association target inference --- scripts/check-association-types.sh | 33 ++++++++++ scripts/check-cakephp-6.sh | 4 ++ scripts/check-consumer.sh | 3 + .../analyzer/association-targets.invalid.php | 49 +++++++++++++++ tests/cakephp6/analyzer.toml | 5 ++ tests/consumer/mago.toml | 1 + tests/consumer/src/AssociationTargetTable.php | 10 ++++ tests/consumer/src/AssociationTargetTypes.php | 44 ++++++++++++++ tests/consumer/vendor/cakephp-types.php | 60 +++++++++++++++++++ 9 files changed, 209 insertions(+) create mode 100755 scripts/check-association-types.sh create mode 100644 tests/analyzer/association-targets.invalid.php create mode 100644 tests/cakephp6/analyzer.toml create mode 100644 tests/consumer/src/AssociationTargetTable.php create mode 100644 tests/consumer/src/AssociationTargetTypes.php create mode 100644 tests/consumer/vendor/cakephp-types.php diff --git a/scripts/check-association-types.sh b/scripts/check-association-types.sh new file mode 100755 index 0000000..60a34c0 --- /dev/null +++ b/scripts/check-association-types.sh @@ -0,0 +1,33 @@ +#!/usr/bin/env bash +set -euo pipefail + +repo_root="$(cd "$(dirname "$0")/.." && pwd)" +mago="$repo_root/vendor/bin/mago" +diagnostics="$(mktemp /tmp/cakephp-mago-associations.XXXXXX)" + +cleanup() { + rm -f "$diagnostics" +} +trap cleanup EXIT + +# Forward Mago's workspace/config options so the same assertions can exercise +# the installed preset's fixture or an actual CakePHP checkout. +"$mago" "$@" analyze --reporting-format short \ + "$repo_root/tests/consumer/src/AssociationTargetTable.php" \ + "$repo_root/tests/consumer/src/AssociationTargetTypes.php" + +if "$mago" "$@" analyze --reporting-format short \ + "$repo_root/tests/consumer/src/AssociationTargetTable.php" \ + "$repo_root/tests/analyzer/association-targets.invalid.php" > "$diagnostics" 2>&1; then + echo "Expected incompatible association target return types to fail analysis." >&2 + exit 1 +fi + +# Each association must resolve to the concrete target, rather than Table or +# mixed. Also reject unexpected errors that could hide a broken test setup. +errors="$(grep -Fc 'error[' "$diagnostics" || true)" +invalid_returns="$(grep -Fc 'error[invalid-return-statement]' "$diagnostics" || true)" +if [[ "$errors" -ne 4 || "$invalid_returns" -ne 4 ]]; then + cat "$diagnostics" >&2 + exit 1 +fi diff --git a/scripts/check-cakephp-6.sh b/scripts/check-cakephp-6.sh index 4ad6114..049ad3d 100755 --- a/scripts/check-cakephp-6.sh +++ b/scripts/check-cakephp-6.sh @@ -75,6 +75,10 @@ config="$repo_root/tests/cakephp6/mago.toml" "$repo_root/vendor/bin/mago" --workspace "$checkout_dir" --config "$config" lint --only \ mago-cakephp/trait-suffix,mago-cakephp/public-method-underscore,mago-cakephp/elseif,mago-cakephp/function-docblock,mago-cakephp/docblock-tag-spacing,mago-cakephp/throws-tag,mago-cakephp/inherit-doc +# Resolve association targets against real CakePHP source without type patches. +bash "$repo_root/scripts/check-association-types.sh" \ + --workspace "$checkout_dir" --config "$repo_root/tests/cakephp6/analyzer.toml" --no-extensions + if [[ "$migration_audit" == true ]]; then echo "Running the full Mago-first preset; findings represent migration work." "$repo_root/vendor/bin/mago" --workspace "$checkout_dir" --config "$repo_root/cakephp.mago.toml" \ diff --git a/scripts/check-consumer.sh b/scripts/check-consumer.sh index 57b69da..7d5ca88 100755 --- a/scripts/check-consumer.sh +++ b/scripts/check-consumer.sh @@ -17,7 +17,10 @@ mago="$repo_root/vendor/bin/mago" "$mago" --workspace "$repo_root" format --check tests/policy "$mago" --workspace "$consumer_dir" extension validate "$mago" --workspace "$consumer_dir" format --check +"$mago" --workspace "$consumer_dir" format --check vendor/cakephp-types.php +"$mago" --workspace "$repo_root" format --check tests/analyzer "$mago" --workspace "$consumer_dir" lint +bash "$repo_root/scripts/check-association-types.sh" --workspace "$consumer_dir" # The installed preset must reject fully qualified classes without --only or # --pedantic, then apply an exact, idempotent native fix. PHPDoc stays unchanged. diff --git a/tests/analyzer/association-targets.invalid.php b/tests/analyzer/association-targets.invalid.php new file mode 100644 index 0000000..cb7b0fe --- /dev/null +++ b/tests/analyzer/association-targets.invalid.php @@ -0,0 +1,49 @@ + $association + */ + public function belongsTo(BelongsTo $association): OtherTargetTable + { + return $association->getTarget(); + } + + /** + * @param BelongsToMany $association + */ + public function belongsToMany(BelongsToMany $association): OtherTargetTable + { + return $association->getTarget(); + } + + /** + * @param HasMany $association + */ + public function hasMany(HasMany $association): OtherTargetTable + { + return $association->getTarget(); + } + + /** + * @param HasOne $association + */ + public function hasOne(HasOne $association): OtherTargetTable + { + return $association->getTarget(); + } +} diff --git a/tests/cakephp6/analyzer.toml b/tests/cakephp6/analyzer.toml new file mode 100644 index 0000000..b9900e8 --- /dev/null +++ b/tests/cakephp6/analyzer.toml @@ -0,0 +1,5 @@ +version = "1.47" +php-version = "8.5" + +[source] +includes = ["src"] diff --git a/tests/consumer/mago.toml b/tests/consumer/mago.toml index 7a4fb90..9f2ee6b 100644 --- a/tests/consumer/mago.toml +++ b/tests/consumer/mago.toml @@ -4,3 +4,4 @@ extends = "vendor/cakephp/mago-rules/cakephp.mago.toml" [source] paths = ["src", "tests"] +includes = ["vendor/cakephp-types.php"] diff --git a/tests/consumer/src/AssociationTargetTable.php b/tests/consumer/src/AssociationTargetTable.php new file mode 100644 index 0000000..7aae5c6 --- /dev/null +++ b/tests/consumer/src/AssociationTargetTable.php @@ -0,0 +1,10 @@ + $association + */ + public function belongsTo(BelongsTo $association): AssociationTargetTable + { + return $association->getTarget(); + } + + /** + * @param BelongsToMany $association + */ + public function belongsToMany(BelongsToMany $association): AssociationTargetTable + { + return $association->getTarget(); + } + + /** + * @param HasMany $association + */ + public function hasMany(HasMany $association): AssociationTargetTable + { + return $association->getTarget(); + } + + /** + * @param HasOne $association + */ + public function hasOne(HasOne $association): AssociationTargetTable + { + return $association->getTarget(); + } +} diff --git a/tests/consumer/vendor/cakephp-types.php b/tests/consumer/vendor/cakephp-types.php new file mode 100644 index 0000000..ff3d78d --- /dev/null +++ b/tests/consumer/vendor/cakephp-types.php @@ -0,0 +1,60 @@ +