TypePHP 编译器 https://swoole.com/aot/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

916 lines
37 KiB

<?php
namespace TypePhp\Tests\NativeClass;
use TypePhp\Exception\TestError;
final class NativeClassValidationTest extends \BaseTest
{
public function testDiscoversNativeTypesBeforeCrossFileSignaturePreprocessing(): void
{
global $translator;
$compiler = \TypePhp\CompilerTest::create(ROOT_PATH);
$translator = $compiler;
$directory = dirname(__DIR__, 2) . '/code/native-class-forward';
$files = [$directory . '/a.php', $directory . '/b.php'];
$compiler->discoverNativeClassDeclarations($files);
foreach ($files as $file) {
$compiler->prepareFile($file);
}
foreach ($files as $file) {
$compiler->convertFile($file);
}
$this->addToAssertionCount(1);
}
public function testRejectsNativeAttributeOnInterface(): void
{
$this->expectException(\TypePhp\Exception\SyntaxError::class);
$this->expectExceptionMessage('Native can only be applied to named classes');
$this->compile('native-class-attribute-interface.php');
}
public function testRejectsNativeAttributeOnTrait(): void
{
$this->expectException(\TypePhp\Exception\SyntaxError::class);
$this->expectExceptionMessage('Native can only be applied to named classes');
$this->compile('native-class-attribute-trait.php');
}
public function testRejectsNativeAttributeOnEnum(): void
{
$this->expectException(\TypePhp\Exception\SyntaxError::class);
$this->expectExceptionMessage('Native can only be applied to named classes');
$this->compile('native-class-attribute-enum.php');
}
public function testRejectsNativeAttributeOnAnonymousClass(): void
{
$this->expectException(\TypePhp\Exception\SyntaxError::class);
$this->expectExceptionMessage('Native can only be applied to named classes');
$this->compile('native-class-anonymous.php');
}
public function testRejectsUntypedProperty(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native class properties must declare a type');
$this->compile('native-class-untyped-property.php');
}
public function testRejectsStaticProperty(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native class static properties are not supported');
$this->compile('native-class-static-property.php');
}
public function testRejectsInheritanceAcrossObjectModels(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native and ZendVM-backed classes cannot inherit from each other');
$this->compile('native-class-zend-inheritance.php');
}
public function testRejectsStaticMethod(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native class static methods are not supported');
$this->compile('native-class-static-method.php');
}
public function testRejectsReadonlyPropertyUntilNativeWriteStateIsImplemented(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native class readonly properties are not supported');
$this->compile('native-class-readonly-property.php');
}
public function testRejectsStdContainerProperty(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native class properties cannot use Std Container types');
$this->compile('native-class-std-container-property.php');
}
public function testRejectsBoxProperty(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native class properties cannot use Box types');
$this->compile('native-class-box-property.php');
}
public function testRejectsNativeStdContainerConversionToPhpArray(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects cannot cross a PHP/ZendVM value boundary');
$this->compile('native-class-std-container-escape.php');
}
public function testRejectsNativeStdContainerPassedAsPhpValue(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects cannot cross a PHP/ZendVM value boundary');
$this->compile('native-class-std-container-argument.php');
}
public function testRejectsReturningStdContainerHoldingNativeObjects(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects cannot cross a PHP/ZendVM value boundary');
$this->compile('native-class-std-container-return.php');
}
public function testRejectsConvertingStdContainerHoldingNativeObjects(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects cannot cross a PHP/ZendVM value boundary');
$this->compile('native-class-std-container-conversion.php');
}
public function testRejectsCapturingStdContainerHoldingNativeObjectsInClosure(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects cannot be captured by Zend closures');
$this->compile('native-class-std-container-closure-capture.php');
}
public function testRejectsCapturingStdContainerHoldingNativeObjectsInArrowFunction(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects cannot be captured by Zend closures');
$this->compile('native-class-std-container-arrow-capture.php');
}
/**
* @dataProvider nativeStdContainerStorageBoundaryProvider
*/
public function testRejectsStoringStdContainerHoldingNativeObjects(string $fixture): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects cannot cross a PHP/ZendVM value boundary');
$this->compile($fixture);
}
public static function nativeStdContainerStorageBoundaryProvider(): array
{
return [
['native-class-std-container-php-property.php'],
['native-class-std-container-static-property.php'],
['native-class-std-container-php-array.php'],
['native-class-std-container-native-any-property.php'],
];
}
public function testRejectsReferencingStdContainerHoldingNativeObjects(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects cannot cross a PHP/ZendVM value boundary');
$this->compile('native-class-std-container-reference.php');
}
public function testRejectsDestructuringStdContainerHoldingNativeObjects(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects cannot cross a PHP/ZendVM value boundary');
$this->compile('native-class-std-container-destructure.php');
}
public function testRejectsStaticStdContainerHoldingNativeObjects(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects must be function-local');
$this->compile('native-class-static-std-container.php');
}
public function testRejectsGlobalStdContainerHoldingNativeObjects(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Std containers holding Native objects must be function-local');
$this->compile('native-class-global-std-container.php');
}
public function testRejectsCompoundWritesToNativePropertyHooks(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native property hooks only support direct reads and assignments');
$this->compile('native-class-property-hook-compound.php');
}
public function testRejectsIssetOnNativePropertyHooks(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('isset()/empty() are not supported for Native property hooks');
$this->compile('native-class-property-hook-isset.php');
}
public function testRejectsIndirectWritesToNativePropertyHooks(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native property hooks only support direct reads and assignments');
$this->compile('native-class-property-hook-indirect-write.php');
}
public function testRejectsIndirectUnsetOnNativePropertyHooks(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native property hooks only support direct reads and assignments');
$this->compile('native-class-property-hook-indirect-unset.php');
}
public function testRejectsIndirectReferencesToNativePropertyHooks(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native property hooks only support direct reads and assignments');
$this->compile('native-class-property-hook-indirect-reference.php');
}
public function testRejectsDynamicInstanceofBecauseNativeClassesHaveNoRuntimeTypeLookup(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Dynamic instanceof is not supported for native objects');
$this->compile('native-class-instanceof.php');
}
public function testRejectsNativeObjectAsDynamicNewTarget(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be used as dynamic class targets');
$this->compile('native-class-dynamic-new.php');
}
public function testRejectsNativeObjectAsDynamicStaticCallTarget(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be used as dynamic class targets');
$this->compile('native-class-dynamic-static-call.php');
}
public function testRejectsNativeObjectAsDynamicClassConstantTarget(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be used as dynamic class targets');
$this->compile('native-class-dynamic-class-constant.php');
}
public function testRejectsNativeObjectStoredInPhpArray(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be stored in PHP arrays');
$this->compile('native-class-php-array.php');
}
public function testRejectsNativeObjectStoredInPhpObjectProperty(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be stored in PHP arrays, PHP object properties');
$this->compile('native-class-php-property.php');
}
public function testRejectsNativeTypedPropertyOnZendObject(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native object types can only be used as properties of native classes');
$this->compile('native-class-zend-native-property.php');
}
public function testRejectsNativeObjectCapturedByClosure(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be captured by Zend closures');
$this->compile('native-class-closure-capture.php');
}
public function testRejectsNativeMethodFirstClassCallable(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native object methods cannot be converted to Zend closures');
$this->compile('native-class-first-class-callable.php');
}
public function testRejectsNativeAbiFunctionFirstClassCallable(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native ABI functions cannot be converted to Zend closures');
$this->compile('native-class-function-first-class-callable.php');
}
public function testRejectsNativeObjectClosureParameter(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Zend closures cannot declare native object parameters or return types');
$this->compile('native-class-closure-parameter.php');
}
public function testRejectsNativeObjectReturnedByUntypedClosure(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Zend closures cannot return native objects');
$this->compile('native-class-closure-return.php');
}
public function testRejectsNativeObjectParameterOnZendConstructor(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Zend-backed constructors cannot accept or return native objects');
$this->compile('native-class-zend-constructor.php');
}
public function testRejectsUnsupportedNativeObjectUnion(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native object types do not support union or intersection declarations; use nullable ?Class syntax');
$this->compile('native-class-union-signature.php');
}
public function testRejectsNativeObjectReferenceParameter(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native object parameters cannot be passed by reference');
$this->compile('native-class-reference-parameter.php');
}
public function testRejectsNativeObjectReferenceReturn(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be returned by reference');
$this->compile('native-class-reference-return.php');
}
public function testRejectsNativeObjectReferenceAssignment(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be referenced; object assignment already shares identity');
$this->compile('native-class-reference-assignment.php');
}
public function testRejectsReferencesToNativeObjectProperties(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Only Native object properties declared as any can be referenced');
$this->compile('native-class-property-reference.php');
}
public function testRejectsReferencesToMixedNativeObjectProperties(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Only Native object properties declared as any can be referenced');
$this->compile('native-class-mixed-property-reference.php');
}
public function testAllowsReferencesToExplicitAnyNativeObjectProperties(): void
{
$this->compile('native-class-any-property-reference.php');
}
public function testRejectsUnsetOnNativeObjectProperties(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native object properties cannot be unset');
$this->compile('native-class-property-unset.php');
}
public function testRejectsExplicitNativeDestructorCall(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Explicit calls to native object destructors are not supported');
$this->compile('native-class-explicit-destructor-call.php');
}
public function testRejectsNativeObjectReferenceKeywordMethod(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be referenced; object assignment already shares identity');
$this->compile('native-class-reference-method.php');
}
public function testRejectsNativeObjectReferenceFunction(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be referenced; object assignment already shares identity');
$this->compile('native-class-reference-function.php');
}
public function testRejectsNativeObjectVariadicParameter(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native object parameters cannot be variadic');
$this->compile('native-class-variadic-parameter.php');
}
public function testRejectsNativeObjectPassedToUntypedParameter(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot cross a PHP/ZendVM argument boundary');
$this->compile('native-class-untyped-parameter.php');
}
public function testRejectsNativeObjectNullUnionInFavorOfNullableSyntax(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native object types do not support union or intersection declarations; use nullable ?Class syntax');
$this->compile('native-class-null-union-parameter.php');
}
public function testRejectsImplicitNullableNativeParameterDefault(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('A Native object parameter with a null default must use explicit nullable ?Class syntax');
$this->compile('native-class-implicit-nullable-parameter.php');
}
public function testRejectsIncorrectNativeKeywordReturnType(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('must return exactly `array`');
$this->compile('native-class-keyword-return-type.php');
}
public function testRejectsMissingNativeKeywordMethod(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('must define `toInt()`');
$this->compile('native-class-keyword-missing.php');
}
public function testRejectsNativeObjectPassedToJsonEncode(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot cross a dynamic PHP/ZendVM call boundary');
$this->compile('native-class-json-encode.php');
}
/**
* @dataProvider nativeZendObjectFacilityProvider
*/
public function testRejectsNativeObjectPassedToZendObjectFacilities(string $fixture): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot cross a dynamic PHP/ZendVM call boundary');
$this->compile($fixture);
}
public static function nativeZendObjectFacilityProvider(): array
{
return [
['native-class-serialize.php'],
['native-class-weak-reference.php'],
];
}
public function testRejectsNativeObjectFromUntypedReturn(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native object return values require an explicit native class return type');
$this->compile('native-class-untyped-return.php');
}
public function testRejectsNativeObjectFromMixedReturn(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native object return values require an explicit native class return type');
$this->compile('native-class-mixed-return.php');
}
public function testRejectsNativeObjectPassedToInterfaceParameter(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be converted to interface `NativeInterfaceArgumentContract`');
$this->compile('native-class-interface-argument.php');
}
public function testRejectsNativeObjectAssignedToInterfaceVariable(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be assigned to interface-typed variables');
$this->compile('native-class-interface-assignment.php');
}
public function testRejectsNativeObjectAssignedToInterfaceProperty(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be assigned to interface-typed properties');
$this->compile('native-class-interface-property.php');
}
public function testRejectsNativeObjectReturnedAsInterface(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be returned as interface `NativeInterfaceReturnContract`');
$this->compile('native-class-interface-return.php');
}
public function testRejectsDynamicMagicMethod(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support dynamic magic method `__get()`');
$this->compile('native-class-dynamic-magic-method.php');
}
public function testRejectsVariableNativeMethodCalls(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Dynamic native object method calls are not supported');
$this->compile('native-class-variable-method.php');
}
public function testRejectsVariableNativePropertyAccess(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Dynamic native object property access is not supported');
$this->compile('native-class-variable-property.php');
}
public function testRejectsDynamicStaticMagicMethodBeforeGenericStaticDiagnostic(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support dynamic magic method `__callStatic()`');
$this->compile('native-class-dynamic-static-magic-method.php');
}
public function testRejectsDynamicMagicMethodInjectedByTrait(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support dynamic magic method `__serialize()`');
$this->compile('native-class-trait-dynamic-magic-method.php');
}
public function testDynamicMagicMethodDenyListIsComplete(): void
{
$trait = new \ReflectionClass(\TypePhp\NativeClass\NativeClassSupportTrait::class);
$constant = $trait->getReflectionConstant('UNSUPPORTED_NATIVE_MAGIC_METHODS');
$this->assertNotFalse($constant);
$this->assertSame([
'__call',
'__callstatic',
'__get',
'__set',
'__isset',
'__unset',
'__sleep',
'__wakeup',
'__serialize',
'__unserialize',
'__set_state',
'__debuginfo',
], array_keys($constant->getValue()));
}
public function testRejectsStaticMethodInjectedByTrait(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native class static methods are not supported');
$this->compile('native-class-trait-static-method.php');
}
public function testRejectsMissingInternalInterfaceMethod(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('must implement method `Countable::count()`');
$this->compile('native-class-internal-interface-missing-method.php');
}
public function testRejectsNonPublicInternalInterfaceMethod(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('must be compatible with `Countable::count()`');
$this->compile('native-class-internal-interface-visibility.php');
}
public function testRejectsNarrowedInternalInterfaceParameter(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('must be compatible with `ArrayAccess::offsetExists()`');
$this->compile('native-class-internal-interface-parameter.php');
}
public function testRejectsExplicitNativeConstructorCall(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Explicit calls to native object constructors are not supported');
$this->compile('native-class-explicit-constructor-call.php');
}
public function testRejectsInternalInterfaceThatPhpClassesCannotImplement(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('cannot implement internal interface `Throwable`');
$this->compile('native-class-non-implementable-interface.php');
}
public function testCountRequiresCountableContract(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('count() requires a native class implementing Countable');
$this->compile('native-class-count-without-countable.php');
}
public function testRejectsNativeLooseEquality(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects do not support the `==` operator; use `===` or `!==` for identity comparison');
$this->compile('native-class-loose-equality.php');
}
public function testRejectsNativeArithmeticOperators(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects do not support the `+` operator');
$this->compile('native-class-arithmetic-operator.php');
}
public function testRejectsNativeUnaryOperators(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects do not support the unary `-` operator');
$this->compile('native-class-unary-operator.php');
}
public function testRejectsIncrementingNativePointerSlots(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects do not support the `++` operator');
$this->compile('native-class-increment.php');
}
public function testRejectsNativeCompoundAssignments(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects do not support the `+=` operator');
$this->compile('native-class-compound-assignment.php');
}
public function testRejectsIncompatibleNativeCoalesceAssignment(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Cannot assign native object `NativeCoalesceWrong` to `NativeCoalesceExpected`');
$this->compile('native-class-coalesce-assign-type.php');
}
public function testRejectsIncompatibleNativePropertyCoalesceAssignment(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Cannot assign object of class `NativeCoalescePropertyWrong` to object property `value` of class `NativeCoalescePropertyExpected`');
$this->compile('native-class-coalesce-property-type.php');
}
public function testRejectsNativeSwitchConditions(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be used as switch values');
$this->compile('native-class-switch.php');
}
public function testRejectsNativeSwitchCaseValues(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be used as switch values');
$this->compile('native-class-switch-case.php');
}
public function testRejectsNativeArrayLiteralKeys(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be used as PHP array keys');
$this->compile('native-class-array-key.php');
}
public function testRejectsNativeArrayDimensionKeys(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be used as PHP array keys');
$this->compile('native-class-array-dim-key.php');
}
public function testRejectsArrayAccessOnNativeObjects(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects do not support array dimension access');
$this->compile('native-class-array-access.php');
}
public function testRejectsArrayWritesOnNativeObjects(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects do not support array dimension access');
$this->compile('native-class-array-access-write.php');
}
public function testRejectsArrayIssetOnNativeObjects(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects do not support array dimension access');
$this->compile('native-class-array-access-isset.php');
}
public function testRejectsArrayUnsetOnNativeObjects(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects do not support array dimension access');
$this->compile('native-class-array-access-unset.php');
}
public function testRejectsInaccessibleNativeCloneMethod(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Call to private NativePrivateClone::__clone()');
$this->compile('native-class-private-clone.php');
}
public function testRejectsNativeObjectReferenceParameterBeforeVirtualAbiGeneration(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native object parameters cannot be passed by reference');
$this->compile('native-class-virtual-byref-variance.php');
}
public function testRejectsNamedArgumentHoleInNativeVirtualCall(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Named calls to Native virtual methods cannot skip an earlier optional parameter');
$this->compile('native-class-virtual-named-gap.php');
}
public function testRejectsLateStaticConstructionInNativeClass(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support `new static()`');
$this->compile('native-class-new-static.php');
}
public function testRejectsGetCalledClassInNativeClass(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support late static binding');
$this->compile('native-class-get-called-class.php');
}
public function testRejectsGetClassForNativeObject(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support runtime class introspection');
$this->compile('native-class-get-class.php');
}
public function testRejectsImplicitGetClassInNativeMethod(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support runtime class introspection');
$this->compile('native-class-get-class-implicit.php');
}
public function testRejectsGetParentClassForNativeObject(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support runtime class introspection');
$this->compile('native-class-get-parent-class.php');
}
public function testRejectsChangingAnInferredNativeGlobalType(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native global/static slot cannot change from `NativeGlobalFirst` to `NativeGlobalSecond`');
$this->compile('native-class-global-type-change.php');
}
public function testRejectsLateStaticConstantResolutionInNativeClass(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support late static binding; use `self::` or a concrete class name');
$this->compile('native-class-late-static-constant.php');
}
public function testRejectsLateStaticNativeMethodSignature(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support late static binding in return types');
$this->compile('native-class-static-signature.php');
}
public function testRejectsLateStaticSignatureInjectedIntoNativeClassByTrait(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native classes do not support late static binding in return types');
$this->compile('native-class-trait-static-signature.php');
}
public function testRejectsInaccessibleNativeClassConstant(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Constant `NativePrivateConstantOwner::VALUE` is not accessible');
$this->compile('native-class-private-constant-access.php');
}
/**
* @dataProvider inaccessibleNativeMethodProvider
*/
public function testRejectsInaccessibleNativeMethods(string $fixture): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Method');
$this->expectExceptionMessage('is not accessible');
$this->compile($fixture);
}
public static function inaccessibleNativeMethodProvider(): array
{
return [
['native-class-private-method-access.php'],
['native-class-protected-method-access.php'],
];
}
public function testRejectsNativeObjectCastToZendObject(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be converted to Zend objects');
$this->compile('native-class-object-cast.php');
}
public function testRejectsErasingNativeObjectTypeWithAny(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be converted to mixed with any()');
$this->compile('native-class-any-escape.php');
}
public function testRejectsBareReturnForNullableNativeObjectType(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('A function with a Native object return type must return a value');
$this->compile('native-class-bare-return.php');
}
public function testRejectsNullForNonNullableNativeObjectReturn(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('The return type is non-nullable native object `NativeNullReturnValue`');
$this->compile('native-class-null-return.php');
}
public function testRejectsNativeObjectGeneratorParameter(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Generator functions cannot accept, capture, or return Native objects');
$this->compile('native-class-generator-parameter.php');
}
public function testRejectsNativeObjectGeneratorMethod(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Generator functions cannot accept, capture, or return Native objects');
$this->compile('native-class-generator-method.php');
}
public function testRejectsNativeObjectConstructionInsideGenerator(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be created inside Generator functions');
$this->compile('native-class-generator-local.php');
}
public function testRejectsNativeObjectRetainedByGeneratorFromFactory(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Generator functions cannot retain Native objects across suspension');
$this->compile('native-class-generator-factory.php');
}
public function testRejectsYieldingNativeObject(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be yielded through a Zend Generator');
$this->compile('native-class-generator-yield.php');
}
public function testRejectsNativeClassReflection(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native class `NativeReflectionClassValue` cannot be used with ReflectionClass');
$this->compile('native-class-reflection-class.php');
}
public function testRejectsNativeMemberReflection(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native class `NativeReflectionMemberValue` cannot be used with ReflectionMethod');
$this->compile('native-class-reflection-member.php');
}
public function testRejectsThrowingNativeObject(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be thrown as Zend exceptions');
$this->compile('native-class-throw.php');
}
public function testRejectsIteratingNativeObjectThroughZendForeach(): void
{
$this->expectException(TestError::class);
$this->expectExceptionMessage('Native objects cannot be iterated by PHP foreach');
$this->compile('native-class-foreach.php');
}
}