*/ public static function changedSignatures(): array { return [ 'extra required parameter' => ['extraRequired'], 'fewer parameters' => ['fewer'], 'parameter type' => ['typeChanged'], 'wider union' => ['unionWidened'], 'return type loses null' => ['notNullable'], 'by reference lost' => ['byValue'], 'variadic lost' => ['notVariadic'], 'default removed' => ['defaultRemoved'], 'return type' => ['returnChanged'], 'no longer static' => ['notStatic'], 'no longer public' => ['notPublic'], ]; } /** @dataProvider changedSignatures */ public function testAnyChangeOfTheInterfaceChangesTheHash(string $variant): void { self::assertNotSame( SignatureFingerprint::of(self::method('base')), SignatureFingerprint::of(self::method($variant)), $variant ); } public function testRenamedParametersAndOtherDefaultValuesKeepTheHash(): void { self::assertSame( SignatureFingerprint::of(self::method('base')), SignatureFingerprint::of(self::method('renamed')) ); } public function testNoTypeReadsAsMixed(): void { self::assertSame( SignatureFingerprint::of(self::method('untyped')), SignatureFingerprint::of(self::method('mixedTyped')) ); } public function testTheCallsOwnArgumentCountAndFeaturesAreNotPartOfIt(): void { self::assertSame( SignatureFingerprint::of(new Call(self::FIXTURE . '::base', 2)), SignatureFingerprint::of(new Call('\\' . self::FIXTURE . '::base', null, [])) ); } public function testAFunctionAndAMethodOfTheSameShapeDiffer(): void { self::assertNotSame( SignatureFingerprint::of(new Call('strlen')), SignatureFingerprint::of(new Call(ArrayObject::class . '::count')) ); } public function testTheClassNeverIncludesAFile(): void { $source = (string) file_get_contents( dirname(__DIR__, 5) . '/src/Integrations/Divi/Release/SignatureFingerprint.php' ); $forbidden = [T_INCLUDE, T_INCLUDE_ONCE, T_REQUIRE, T_REQUIRE_ONCE, T_EVAL]; foreach (token_get_all($source) as $token) { self::assertFalse(is_array($token) && in_array($token[0], $forbidden, true), 'no include, require or eval'); } } }