addFiles([$testFile]); $compiler->prepareFile($testFile); $compiler->convertFile($testFile); $this->addToAssertionCount(1); return ROOT_PATH . '/build/phpunit/code/' . basename($file, '.php') . '.cc'; } public function testFindNativePropertyUsesFullClassNameAcrossBranches(): void { try { $this->compileNativeProperty('native-property-full-name.php'); } catch (TestError $e) { $this->fail($e->getMessage()); } } public function testStaticStaticPropertyUsesDynamicCalledClassPath(): void { try { $outputFile = $this->compileNativeProperty('native-property-full-name.php'); } catch (TestError $e) { $this->fail($e->getMessage()); } $code = file_get_contents($outputFile); $this->assertStringContainsString('php::getStaticProperty(php_get_called_class(this_), "count")', $code); $this->assertStringContainsString('php::getStaticProperty(php_get_called_class(this_), "count") = php::toInt(value)', $code); } public function testNativeIntPropertyAssignOpUsesNativeReference(): void { try { $outputFile = $this->compileNativeProperty('native-property-assign-op-int.php'); } catch (TestError $e) { $this->fail($e->getMessage()); } $code = file_get_contents($outputFile); $this->assertStringContainsString('typephp_static_int_ref(this_.attr(', $code); $this->assertStringContainsString('typephp_static_int_ref(box.attr(', $code); $this->assertSame(2, substr_count($code, 'typephp_static_int_ref(')); $this->assertStringNotContainsString('this_.attr(php_get_prop(0, _literal_strings[0], 0, _literal_strings[1]), true) +=', $code); $this->assertStringNotContainsString('box.attr(php_get_prop(0, _literal_strings[0], 0, _literal_strings[1]), true) +=', $code); } public function testNativeIntPropertyAssignOpConvertsBitwiseNotClassConst(): void { try { $outputFile = $this->compileNativeProperty('native-property-assign-op-class-const.php'); } catch (TestError $e) { $this->fail($e->getMessage()); } $code = file_get_contents($outputFile); $this->assertStringContainsString('typephp_static_int_ref(this_.attr(', $code); $this->assertStringContainsString('&= (~php::toInt(php::constant(', $code); } public function testNativePropertyWriteConvertsOnlyWhenTypesDiffer(): void { try { $outputFile = $this->compileNativeProperty('native-property-write-conversion.php'); } catch (TestError $e) { $this->fail($e->getMessage()); } $code = file_get_contents($outputFile); $this->assertStringContainsString(' = nativeValue;', $code); $this->assertStringContainsString(' = php::toIntExact(dynamicValue, "NativePropertyWriteConversionBox::$value");', $code); $this->assertStringNotContainsString(' = php::toInt(nativeValue);', $code); } public function testNativeThisPropertyWriteUsesExactHelperOnNativeReference(): void { try { $outputFile = $this->compileNativeProperty('native-property-this-write-conversion.php'); } catch (TestError $e) { $this->fail($e->getMessage()); } $code = file_get_contents($outputFile); $this->assertStringContainsString('php::Int &_object_prop_this___value = Z_LVAL_P(this_.attr(', $code); $this->assertStringContainsString('_object_prop_this___value = php::toIntExact(dynamicValue, "NativePropertyThisWriteConversionBox::$value");', $code); } public function testNativePropertyStaticScalarTypeMismatchFailsAtCompileTime(): void { $this->exec( 'Cannot assign string to property NativePropertyStaticTypeMismatchBox::$value of type int', 'native-property-static-type-mismatch.php' ); } public function testCannotAccessPrivateNativePropertyFromUnrelatedClass(): void { $this->exec('Cannot access private property `value` of class `NativePrivateOwner`', 'native-property-private-other-class.php'); } public function testCannotAccessProtectedNativePropertyFromUnrelatedClass(): void { $this->exec('Cannot access protected property `value` of class `NativeProtectedOwner`', 'native-property-protected-unrelated-class.php'); } public function testCannotAccessPrivateNativePropertyThroughNullsafe(): void { $this->exec('Cannot access private property `value` of class `NullsafePrivateOwner`', 'nullsafe-private-property.php'); } public function testCannotAccessNestedPrivateNativePropertyThroughNullsafe(): void { $this->exec('Cannot access private property `value` of class `NullsafeNestedChild`', 'nullsafe-nested-private-property.php'); } public function testCannotAssignThroughNullsafeProperty(): void { $this->exec("Can't use nullsafe operator in write context", 'nullsafe-write-assign.php'); } public function testCannotUseCompoundAssignThroughNullsafeProperty(): void { $this->exec("Can't use nullsafe operator in write context", 'nullsafe-write-assign-op.php'); } public function testCannotIncrementThroughNullsafeProperty(): void { $this->exec("Can't use nullsafe operator in write context", 'nullsafe-write-inc.php'); } public function testCannotUnsetThroughNullsafeProperty(): void { $this->exec("Can't use nullsafe operator in write context", 'nullsafe-write-unset.php'); } public function testCannotAssignReferenceToNullsafeProperty(): void { $this->exec("Can't use nullsafe operator in write context", 'nullsafe-write-assign-ref-left.php'); } public function testCannotTakeReferenceOfNullsafeProperty(): void { $this->exec('Cannot take reference of a nullsafe chain', 'nullsafe-write-assign-ref-right.php'); } }