diff --git a/src/Constraint/AccessorPairConstraint.php b/src/Constraint/AccessorPairConstraint.php
index 7402021..d9ec592 100644
--- a/src/Constraint/AccessorPairConstraint.php
+++ b/src/Constraint/AccessorPairConstraint.php
@@ -13,6 +13,7 @@
use Doctrine\Inflector\InflectorFactory;
use Exception;
use LogicException;
+use phpDocumentor\Reflection\Types\Object_;
use PHPUnit\Framework\Constraint\Constraint;
use ReflectionClass;
use ReflectionMethod;
@@ -283,6 +284,14 @@ protected function getTestValues(ReflectionMethod $method, ReflectionParameter $
$resolver = new TypehintResolver($method);
$typehint = $resolver->getParamTypehint($parameter);
+ $valueProvider = $this->config->getValueProvider();
+ if ($valueProvider !== null && $typehint instanceof Object_) {
+ $value = $valueProvider(ltrim((string)$typehint->getFqsen(), '\\'));
+ if ($value !== null) {
+ return [$value];
+ }
+ }
+
return $this->valueProviderFactory->getProvider($typehint)->getValues();
}
diff --git a/src/Constraint/ConstraintConfig.php b/src/Constraint/ConstraintConfig.php
index 3e391d1..5663db4 100644
--- a/src/Constraint/ConstraintConfig.php
+++ b/src/Constraint/ConstraintConfig.php
@@ -23,6 +23,9 @@ class ConstraintConfig
/** @var null|callable(): mixed[] */
private $constructorCallback = null;
+ /** @var null|(callable(class-string): ?object) */
+ private $valueProvider = null;
+
public function hasAccessorPairCheck(): bool
{
return $this->assertAccessorPair;
@@ -129,4 +132,23 @@ public function setConstructorCallback(callable $callback): self
return $this;
}
+
+ public function getValueProvider(): ?callable
+ {
+ return $this->valueProvider;
+ }
+
+ /**
+ * Callback function to allow for a custom value provider. For instance for final classes. The argument
+ * is the class-string of the value, the return value should be the provided value. Return null
+ * to skip the value provider and use the default value providers.
+ *
+ * @param callable(class-string): ?object $valueProvider
+ */
+ public function setValueProvider(callable $valueProvider): self
+ {
+ $this->valueProvider = $valueProvider;
+
+ return $this;
+ }
}
diff --git a/tests/Integration/AccessorPairAsserterTest.php b/tests/Integration/AccessorPairAsserterTest.php
index 8d50464..042b086 100644
--- a/tests/Integration/AccessorPairAsserterTest.php
+++ b/tests/Integration/AccessorPairAsserterTest.php
@@ -6,6 +6,7 @@
use DigitalRevolution\AccessorPairConstraint\AccessorPairAsserter;
use DigitalRevolution\AccessorPairConstraint\Constraint\ConstraintConfig;
use DigitalRevolution\AccessorPairConstraint\Tests\Integration\data\manual\CustomConstructorParameters;
+use DigitalRevolution\AccessorPairConstraint\Tests\Integration\data\manual\FinalClass;
use DigitalRevolution\AccessorPairConstraint\Tests\Integration\data\manual\IntersectionClassProperty;
use DigitalRevolution\AccessorPairConstraint\Tests\Integration\data\manual\IntersectionInterfaceProperty;
use DigitalRevolution\AccessorPairConstraint\Tests\Integration\data\manual\SetterTransformer;
@@ -101,7 +102,6 @@ public function testMatchesSuccessInitialStateWithDefaultMethod(object $class):
/**
* When turning off the propertyDefaultCheck, we can safely pass classes we know will fail the constraint
- *
* @dataProvider failureInitialStateDataProvider
*/
public function testExcludingInitialStateCheck(object $class): void
@@ -119,7 +119,6 @@ public function testMatchesSuccessConstructorPair(object $class): void
/**
* When turning off the constructorPairCheck, we can safely pass classes we know will fail the constraint
- *
* @dataProvider failureConstructorDataProvider
*/
public function testExcludingConstructorPair(object $class): void
@@ -196,6 +195,14 @@ public function testIntersectionClassProperty(): void
static::assertAccessorPairs(IntersectionClassProperty::class);
}
+ public function testFinalClassWithCustomValueProvider(): void
+ {
+ $config = new ConstraintConfig();
+ $config->setValueProvider(static fn(string $class) => $class === FinalClass::class ? new FinalClass() : null);
+
+ static::assertAccessorPairs(FinalClass::class, $config);
+ }
+
/**
* @return Generator>
* @throws ReflectionException
diff --git a/tests/Integration/data/manual/FinalClass.php b/tests/Integration/data/manual/FinalClass.php
new file mode 100644
index 0000000..538a028
--- /dev/null
+++ b/tests/Integration/data/manual/FinalClass.php
@@ -0,0 +1,31 @@
+intValue;
+ }
+
+ public function setIntValue(int $intValue): void
+ {
+ $this->intValue = $intValue;
+ }
+
+ public function getProperty(): FinalClass
+ {
+ return $this->property;
+ }
+
+ public function setProperty(FinalClass $property): void
+ {
+ $this->property = $property;
+ }
+}