$types * */ public function testValidTypeCombination($expected, $types): void { $converted_types = []; foreach ($types as $type) { $converted_type = self::getAtomic($type); $converted_type->from_docblock = true; $converted_types[] = $converted_type; } $this->assertSame( $expected, TypeCombiner::combine($converted_types)->getId() ); } /** * @return iterable,error_levels?:string[]}> */ public function providerValidCodeParse(): iterable { return [ 'multipleValuedArray' => [ ' [ ' [ ' [ ' $_a */ function expectsTraversableOrArray($_a): void { } ', ], ]; } /** * @return array}> */ public function providerTestValidTypeCombination(): array { return [ 'intOrString' => [ 'int|string', [ 'int', 'string', ], ], 'mixedOrNull' => [ 'mixed|null', [ 'mixed', 'null', ], ], 'mixedOrEmpty' => [ 'mixed', [ 'empty', 'mixed', ], ], 'mixedOrObject' => [ 'mixed|object', [ 'mixed', 'object', ], ], 'mixedOrEmptyArray' => [ 'array|mixed', [ 'mixed', 'array', ], ], 'falseTrueToBool' => [ 'bool', [ 'false', 'true', ], ], 'trueFalseToBool' => [ 'bool', [ 'true', 'false', ], ], 'trueBoolToBool' => [ 'bool', [ 'true', 'bool', ], ], 'boolTrueToBool' => [ 'bool', [ 'bool', 'true', ], ], 'intOrTrueOrFalseToBool' => [ 'bool|int', [ 'int', 'false', 'true', ], ], 'intOrBoolOrTrueToBool' => [ 'bool|int', [ 'int', 'bool', 'true', ], ], 'intOrTrueOrBoolToBool' => [ 'bool|int', [ 'int', 'true', 'bool', ], ], 'arrayOfIntOrString' => [ 'array', [ 'array', 'array', ], ], 'arrayOfIntOrAlsoString' => [ 'array|string', [ 'array', 'string', ], ], 'emptyArrays' => [ 'array', [ 'array', 'array', ], ], 'arrayStringOrEmptyArray' => [ 'array', [ 'array', 'array', ], ], 'arrayMixedOrString' => [ 'array', [ 'array', 'array', ], ], 'arrayMixedOrStringKeys' => [ 'array', [ 'array', 'array', ], ], 'arrayMixedOrEmpty' => [ 'array', [ 'array', 'array', ], ], 'arrayBigCombination' => [ 'array', [ 'array', 'array', ], ], 'arrayTraversableToIterable' => [ 'iterable', [ 'array', 'Traversable', ], ], 'arrayIterableToIterable' => [ 'iterable', [ 'array', 'iterable', ], ], 'iterableArrayToIterable' => [ 'iterable', [ 'iterable', 'array', ], ], 'traversableIterableToIterable' => [ 'iterable', [ 'Traversable', 'iterable', ], ], 'iterableTraversableToIterable' => [ 'iterable', [ 'iterable', 'Traversable', ], ], 'arrayTraversableToIterableWithParams' => [ 'iterable', [ 'array', 'Traversable', ], ], 'arrayIterableToIterableWithParams' => [ 'iterable', [ 'array', 'iterable', ], ], 'iterableArrayToIterableWithParams' => [ 'iterable', [ 'iterable', 'array', ], ], 'traversableIterableToIterableWithParams' => [ 'iterable', [ 'Traversable', 'iterable', ], ], 'iterableTraversableToIterableWithParams' => [ 'iterable', [ 'iterable', 'Traversable', ], ], 'arrayObjectAndParamsWithEmptyArray' => [ 'ArrayObject|array', [ 'ArrayObject', 'array', ], ], 'emptyArrayWithArrayObjectAndParams' => [ 'ArrayObject|array', [ 'array', 'ArrayObject', ], ], 'falseDestruction' => [ 'bool', [ 'false', 'bool', ], ], 'onlyFalse' => [ 'false', [ 'false', ], ], 'onlyTrue' => [ 'true', [ 'true', ], ], 'falseFalseDestruction' => [ 'false', [ 'false', 'false', ], ], 'aAndAOfB' => [ 'A|A', [ 'A', 'A', ], ], 'combineObjectType1' => [ 'array{a?: int, b?: string}', [ 'array{a: int}', 'array{b: string}', ], ], 'combineObjectType2' => [ 'array{a: int|string, b?: string}', [ 'array{a: int}', 'array{a: string,b: string}', ], ], 'combineObjectTypeWithIntKeyedArray' => [ 'array<"a"|int, int|string>', [ 'array{a: int}', 'array', ], ], 'combineNestedObjectTypeWithTKeyedArrayIntKeyedArray' => [ 'array{a: array<"a"|int, int|string>}', [ 'array{a: array{a: int}}', 'array{a: array}', ], ], 'combineIntKeyedObjectTypeWithNestedIntKeyedArray' => [ 'array>', [ 'array', 'array>', ], ], 'combineNestedObjectTypeWithNestedIntKeyedArray' => [ 'array<"a"|int, array<"a"|int, int|string>>', [ 'array{a: array{a: int}}', 'array>', ], ], 'combinePossiblyUndefinedKeys' => [ 'array{a: bool, b?: mixed, d?: mixed}', [ 'array{a: false, b: mixed}', 'array{a: true, d: mixed}', 'array{a: true, d: mixed}', ], ], 'combinePossiblyUndefinedKeysAndString' => [ 'array{a: string, b?: int}|string', [ 'array{a: string, b?: int}', 'string', ], ], 'combineMixedArrayWithTKeyedArray' => [ 'array', [ 'array{a: int}', 'array', ], ], 'traversableAorB' => [ 'Traversable', [ 'Traversable', 'Traversable', ], ], 'iterableAorB' => [ 'iterable', [ 'iterable', 'iterable', ], ], 'FooAorB' => [ 'Foo|Foo', [ 'Foo', 'Foo', ], ], 'traversableOfMixed' => [ 'Traversable', [ 'Traversable', 'Traversable', ], ], 'traversableAndIterator' => [ 'Traversable&Iterator', [ 'Traversable&Iterator', 'Traversable&Iterator', ], ], 'traversableOfMixedAndIterator' => [ 'Traversable&Iterator', [ 'Traversable&Iterator', 'Traversable&Iterator', ], ], 'objectLikePlusArrayEqualsArray' => [ 'array<"a"|"b"|"c", 1|2|3>', [ 'array<"a"|"b"|"c", 1|2|3>', 'array{a: 1|2, b: 2|3, c: 1|3}', ], ], 'combineClosures' => [ 'Closure(A):void|Closure(B):void', [ 'Closure(A):void', 'Closure(B):void', ], ], 'combineClassStringWithString' => [ 'string', [ 'class-string', 'string', ], ], 'combineClassStringWithFalse' => [ 'class-string|false', [ 'class-string', 'false', ], ], 'combineRefinedClassStringWithString' => [ 'string', [ 'class-string', 'string', ], ], 'combineRefinedClassStrings' => [ 'class-string|class-string', [ 'class-string', 'class-string', ], ], 'combineClassStringsWithLiteral' => [ 'class-string', [ 'class-string', 'Exception::class', ], ], 'combineClassStringWithNumericString' => [ 'class-string|numeric-string', [ 'class-string', 'numeric-string', ], ], 'combineRefinedClassStringWithNumericString' => [ 'class-string|numeric-string', [ 'class-string', 'numeric-string', ], ], 'combineClassStringWithTraitString' => [ 'class-string|trait-string', [ 'class-string', 'trait-string', ], ], 'combineRefinedClassStringWithTraitString' => [ 'class-string|trait-string', [ 'class-string', 'trait-string', ], ], 'combineCallableAndCallableString' => [ 'callable', [ 'callable', 'callable-string', ], ], 'combineCallableStringAndCallable' => [ 'callable', [ 'callable-string', 'callable' ], ], 'combineCallableAndCallableObject' => [ 'callable', [ 'callable', 'callable-object', ], ], 'combineCallableObjectAndCallable' => [ 'callable', [ 'callable-object', 'callable' ], ], 'combineCallableAndCallableArray' => [ 'callable', [ 'callable', 'callable-array', ], ], 'combineCallableArrayAndCallable' => [ 'callable', [ 'callable-array', 'callable' ], ], 'combineCallableArrayAndArray' => [ 'array', [ 'callable-array{class-string, string}', 'array', ], ], 'combineGenericArrayAndMixedArray' => [ 'array', [ 'array', 'array', ], ], 'combineTKeyedArrayAndArray' => [ 'array', [ 'array{hello: int}', 'array', ], ], 'combineTKeyedArrayAndNestedArray' => [ 'array', [ 'array{hello: array{goodbye: int}}', 'array', ], ], 'combineNumericStringWithLiteralString' => [ 'numeric-string', [ 'numeric-string', '"1"', ], ], 'combineLiteralStringWithNumericString' => [ 'numeric-string', [ '"1"', 'numeric-string', ], ], 'combineNonEmptyListWithTKeyedArrayList' => [ 'array{0: null|string}', [ 'non-empty-list', 'array{null}' ], ], 'combineZeroAndPositiveInt' => [ '0|positive-int', [ '0', 'positive-int', ], ], 'combinePositiveIntAndZero' => [ '0|positive-int', [ 'positive-int', '0', ], ], 'combinePositiveIntAndMinusOne' => [ 'int', [ 'positive-int', '-1', ], ], 'combinePositiveIntZeroAndMinusOne' => [ 'int', [ '0', 'positive-int', '-1', ], ], 'combineMinusOneAndPositiveInt' => [ 'int', [ '-1', 'positive-int', ], ], 'combineZeroMinusOneAndPositiveInt' => [ 'int', [ '0', '-1', 'positive-int', ], ], 'combineZeroOneAndPositiveInt' => [ '0|positive-int', [ '0', '1', 'positive-int', ], ], 'combinePositiveIntOneAndZero' => [ '0|positive-int', [ 'positive-int', '1', '0', ], ], 'combinePositiveInts' => [ 'positive-int', [ 'positive-int', 'positive-int', ], ], 'combineNonEmptyArrayAndKeyedArray' => [ 'array', [ 'non-empty-array', 'array{0?:int}', ] ], 'combineNonEmptyStringAndLiteral' => [ 'non-empty-string', [ 'non-empty-string', '"foo"', ] ], 'combineLiteralAndNonEmptyString' => [ 'non-empty-string', [ '"foo"', 'non-empty-string' ] ], 'combineNonFalsyNonEmptyString' => [ 'non-empty-string', [ 'non-falsy-string', 'non-empty-string' ] ], 'combineNonEmptyNonFalsyString' => [ 'non-empty-string', [ 'non-empty-string', 'non-falsy-string' ] ], 'combineNonEmptyStringAndNumericString' => [ 'non-empty-string', [ 'non-empty-string', 'numeric-string' ] ], 'combineNumericStringAndNonEmptyString' => [ 'non-empty-string', [ 'numeric-string', 'non-empty-string' ] ], 'combineNonEmptyLowercaseAndNonFalsyString' => [ 'non-empty-string', [ 'non-falsy-string', 'non-empty-lowercase-string', ] ], 'combineNonEmptyAndEmptyScalar' => [ 'scalar', [ 'non-empty-scalar', 'empty-scalar', ] ], 'combineLiteralStringAndNonspecificLiteral' => [ 'literal-string', [ 'literal-string', '"foo"', ] ], 'combineNonspecificLiteralAndLiteralString' => [ 'literal-string', [ '"foo"', 'literal-string', ] ], 'combineLiteralIntAndNonspecificLiteral' => [ 'literal-int', [ 'literal-int', '5', ] ], 'combineNonspecificLiteralAndLiteralInt' => [ 'literal-int', [ '5', 'literal-int', ] ], 'combineNonspecificLiteralAndPositiveInt' => [ 'int', [ 'positive-int', 'literal-int', ] ], 'combinePositiveAndLiteralInt' => [ 'int', [ 'literal-int', 'positive-int', ] ], ]; } /** * @param string $string * */ private static function getAtomic($string): Type\Atomic { return array_values(Type::parseString($string)->getAtomicTypes())[0]; } }