All Downloads are FREE. Search and download functionalities are using the official Maven repository.

php-slim4-server.openapi_data_mocker_test.mustache Maven / Gradle / Ivy

The newest version!
mock($dataType, $dataFormat, $options);
        $this->assertInternalType($expectedType, $data);
    }

    public function provideMockCorrectArguments()
    {
        return [
            [IMocker::DATA_TYPE_INTEGER, null, null, IsType::TYPE_INT],
            [IMocker::DATA_TYPE_NUMBER, null, null, IsType::TYPE_FLOAT],
            [IMocker::DATA_TYPE_STRING, null, null, IsType::TYPE_STRING],
            [IMocker::DATA_TYPE_BOOLEAN, null, null, IsType::TYPE_BOOL],
            [IMocker::DATA_TYPE_ARRAY, null, [
                'items' => [
                    'type' => IMocker::DATA_TYPE_INTEGER,
                ],
            ], IsType::TYPE_ARRAY],
            [IMocker::DATA_TYPE_OBJECT, null, [
                'properties' => [
                    'username' => [
                        'type' => IMocker::DATA_TYPE_INTEGER,
                    ],
                ],
            ], IsType::TYPE_OBJECT],
        ];
    }

    /**
     * @covers ::mock
     * @dataProvider provideMockInvalidArguments
     * @expectedException \InvalidArgumentException
     * @expectedExceptionMessage "dataType" must be one of integer, number, string, boolean, array, object
     */
    public function testMockInvalidArguments($dataType, $dataFormat, $options)
    {
        $mocker = new OpenApiDataMocker();
        $data = $mocker->mock($dataType, $dataFormat, $options);
    }

    public function provideMockInvalidArguments()
    {
        return [
            ['foobar', null, null],
            [3.14, null, null],
            [null, null, null],
        ];
    }

    /**
     * @covers ::mock
     */
    public function testMockWithStringEnumOptions()
    {
        $mocker = new OpenApiDataMocker();
        $string = $mocker->mock(IMocker::DATA_TYPE_STRING, null, [
            'enum' => ['foobar', 'foobaz', 'helloworld'],
        ]);
        $this->assertContains($string, ['foobar', 'foobaz', 'helloworld']);
    }

    /**
     * @dataProvider provideMockIntegerCorrectArguments
     * @covers ::mockInteger
     */
    public function testMockIntegerWithCorrectArguments(
        $dataFormat = null,
        $minimum = null,
        $maximum = null,
        $exclusiveMinimum = false,
        $exclusiveMaximum = false,
        $matchingInternalTypes = [],
        $notMatchingInternalTypes = []
    ) {
        $mocker = new OpenApiDataMocker();
        $integer = $mocker->mockInteger($dataFormat, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);

        $this->internalAssertNumber(
            $integer,
            $minimum,
            $maximum,
            $exclusiveMinimum,
            $exclusiveMaximum,
            $matchingInternalTypes,
            $notMatchingInternalTypes
        );
    }

    public function provideMockIntegerCorrectArguments()
    {
        $types = [
            IsType::TYPE_INT,
            IsType::TYPE_NUMERIC,
            IsType::TYPE_SCALAR,
        ];
        $notTypes = [
            IsType::TYPE_ARRAY,
            IsType::TYPE_BOOL,
            IsType::TYPE_FLOAT,
            IsType::TYPE_NULL,
            IsType::TYPE_OBJECT,
            IsType::TYPE_RESOURCE,
            IsType::TYPE_STRING,
            IsType::TYPE_CALLABLE,
        ];

        return [
            [null, -100, 100, false, false, $types, $notTypes],
            [null, -100, null, false, false, $types, $notTypes],
            [null, null, 100, false, false, $types, $notTypes],
            [null, -99.5, null, true, false, $types, $notTypes],
            [null, null, 99.5, false, true, $types, $notTypes],
            [null, -99.5, 99.5, true, true, $types, $notTypes],
        ];
    }

    /**
     * @dataProvider provideMockIntegerInvalidArguments
     * @covers ::mockInteger
     * @expectedException \InvalidArgumentException
     */
    public function testMockIntegerWithInvalidArguments(
        $dataFormat = null,
        $minimum = null,
        $maximum = null,
        $exclusiveMinimum = false,
        $exclusiveMaximum = false
    ) {
        $mocker = new OpenApiDataMocker();
        $integer = $mocker->mockInteger($dataFormat, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);
    }

    public function provideMockIntegerInvalidArguments()
    {
        return [
            [null, 'foo', null, false, false],
            [null, null, false, false, false],
            [null, null, null, true, false],
            [null, null, null, false, true],
            [null, 100, -100, false, false],
        ];
    }

    /**
     * @covers ::mockInteger
     * @dataProvider provideMockIntegerFormats
     */
    public function testMockIntegerWithFormats(
        $dataFormat,
        $minimum,
        $maximum,
        $expectedMin,
        $expectedMax
    ) {
        $mocker = new OpenApiDataMocker();
        $integer = $mocker->mockInteger($dataFormat, $minimum, $maximum);
        $this->assertGreaterThanOrEqual($expectedMin, $integer);
        $this->assertLessThanOrEqual($expectedMax, $integer);
    }

    public function provideMockIntegerFormats()
    {
        return [
            [IMocker::DATA_FORMAT_INT32, -2147483648, 2147483648, -2147483647, 2147483647],
            [IMocker::DATA_FORMAT_INT64, '-9223372036854775808', '9223372036854775808', -9223372036854775807, 9223372036854775807],
            [IMocker::DATA_FORMAT_INT32, -10, 10, -10, 10],
            [IMocker::DATA_FORMAT_INT64, -10, 10, -10, 10],
            [IMocker::DATA_FORMAT_INT32, -9223372036854775807, 9223372036854775807, -2147483647, 2147483647],
            [strtoupper(IMocker::DATA_FORMAT_INT32), -2147483648, 2147483648, -2147483647, 2147483647],
            [strtoupper(IMocker::DATA_FORMAT_INT64), '-9223372036854775808', '9223372036854775808', -9223372036854775807, 9223372036854775807],
        ];
    }

    /**
     * @dataProvider provideMockNumberCorrectArguments
     * @covers ::mockNumber
     */
    public function testMockNumberWithCorrectArguments(
        $dataFormat = null,
        $minimum = null,
        $maximum = null,
        $exclusiveMinimum = false,
        $exclusiveMaximum = false,
        $matchingInternalTypes = [],
        $notMatchingInternalTypes = []
    ) {
        $mocker = new OpenApiDataMocker();
        $number = $mocker->mockNumber($dataFormat, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);

        $this->internalAssertNumber(
            $number,
            $minimum,
            $maximum,
            $exclusiveMinimum,
            $exclusiveMaximum,
            $matchingInternalTypes,
            $notMatchingInternalTypes
        );
    }

    public function provideMockNumberCorrectArguments()
    {
        $types = [
            IsType::TYPE_SCALAR,
            IsType::TYPE_NUMERIC,
            IsType::TYPE_FLOAT,
        ];
        $notTypes = [
            IsType::TYPE_INT,
            IsType::TYPE_ARRAY,
            IsType::TYPE_BOOL,
            IsType::TYPE_NULL,
            IsType::TYPE_OBJECT,
            IsType::TYPE_RESOURCE,
            IsType::TYPE_STRING,
            IsType::TYPE_CALLABLE,
        ];

        return [
            [null, -100, 100, false, false, $types, $notTypes],
            [null, -100, null, false, false, $types, $notTypes],
            [null, null, 100, false, false, $types, $notTypes],
            [null, -99.5, null, true, false, $types, $notTypes],
            [null, null, 99.5, false, true, $types, $notTypes],
            [null, -99.5, 99.5, true, true, $types, $notTypes],
        ];
    }

    /**
     * @dataProvider provideMockNumberInvalidArguments
     * @expectedException \InvalidArgumentException
     * @covers ::mockNumber
     */
    public function testMockNumberWithInvalidArguments(
        $dataFormat = null,
        $minimum = null,
        $maximum = null,
        $exclusiveMinimum = false,
        $exclusiveMaximum = false
    ) {
        $mocker = new OpenApiDataMocker();
        $number = $mocker->mockNumber($dataFormat, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);
    }

    public function provideMockNumberInvalidArguments()
    {
        return [
            [null, 'foo', null, false, false],
            [null, null, false, false, false],
            [null, null, null, true, false],
            [null, null, null, false, true],
            [null, 100, -100, false, false],
        ];
    }

    /**
     * @dataProvider provideMockStringCorrectArguments
     * @covers ::mockString
     */
    public function testMockStringWithCorrectArguments(
        $dataFormat = null,
        $minLength = 0,
        $maxLength = null,
        $enum = null,
        $matchingInternalTypes = [],
        $notMatchingInternalTypes = []
    ) {
        $mocker = new OpenApiDataMocker();
        $str = $mocker->mockString($dataFormat, $minLength, $maxLength, $enum);

        $this->internalAssertString(
            $str,
            $minLength,
            $maxLength,
            $enum,
            $matchingInternalTypes,
            $notMatchingInternalTypes
        );
    }

    public function provideMockStringCorrectArguments()
    {
        $types = [
            IsType::TYPE_SCALAR,
            IsType::TYPE_STRING,
        ];
        $notTypes = [
            IsType::TYPE_FLOAT,
            IsType::TYPE_INT,
            IsType::TYPE_ARRAY,
            IsType::TYPE_BOOL,
            IsType::TYPE_NULL,
            IsType::TYPE_OBJECT,
            IsType::TYPE_RESOURCE,
            IsType::TYPE_CALLABLE,
        ];

        return [
            [null, 0, null, null, $types, $notTypes],
            [null, 10, null, null, $types, $notTypes],
            [null, 0, 100, null, $types, $notTypes],
            [null, 10, 50, null, $types, $notTypes],
            [null, 10, 10, null, $types, $notTypes],
            [null, 0, 0, null, $types, $notTypes],
            [null, null, null, null, $types, $notTypes],
            [null, null, null, ['foobar', 'foobaz', 'hello world'], $types, $notTypes],
            [null, null, null, ['foobar'], $types, $notTypes],
            [IMocker::DATA_FORMAT_PASSWORD, 0, null, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_PASSWORD, 10, null, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_PASSWORD, 0, 100, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_PASSWORD, 10, 50, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_PASSWORD, 10, 10, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_PASSWORD, 0, 0, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_EMAIL, null, null, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_EMAIL, 10, null, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_EMAIL, 10, 10, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_EMAIL, null, 8, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_EMAIL, 16, null, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_EMAIL, 25, null, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_EMAIL, 25, 25, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_EMAIL, null, 20, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_EMAIL, 30, null, null, $types, $notTypes],
            [IMocker::DATA_FORMAT_EMAIL, 1, 1, null, $types, $notTypes],
        ];
    }

    /**
     * @dataProvider provideMockStringInvalidArguments
     * @expectedException \InvalidArgumentException
     * @covers ::mockString
     */
    public function testMockStringWithInvalidArguments(
        $dataFormat = null,
        $minLength = 0,
        $maxLength = null,
        $enum = null
    ) {
        $mocker = new OpenApiDataMocker();
        $str = $mocker->mockString($dataFormat, $minLength, $maxLength, $enum);
    }

    public function provideMockStringInvalidArguments()
    {
        return [
            'negative minLength' => [null, -10, null],
            'negative maxLength' => [null, 0, -10],
            'both minLength maxLength negative' => [null, -10, -10],
            'decimal minLength and maxLength' => [null, 0.5, 0.5],
            'string minLength' => [null, '10', null],
            'string maxLength' => [null, 0, '50'],
            'string minLength and maxLength' => [null, '10', '50'],
            'maxLength less than minLength' => [null, 50, 10],
            'enum is string' => [null, null, null, 'foobar'],
            'enum is empty array' => [null, null, null, []],
            'enum array is not unique' => [null, null, null, ['foobar', 'foobaz', 'foobar']],
        ];
    }

    /**
     * @covers ::mock
     * @covers ::mockString
     * @dataProvider provideMockStringByteFormatArguments
     */
    public function testMockStringWithByteFormat(
        $dataFormat,
        $minLength,
        $maxLength
    ) {
        $mocker = new OpenApiDataMocker();
        $str = $mocker->mockString($dataFormat, $minLength, $maxLength);
        $str2 = $mocker->mock(IMocker::DATA_TYPE_STRING, $dataFormat, ['minLength' => $minLength, 'maxLength' => $maxLength]);
        $base64pattern = '/^[\w\+\/\=]*$/';
        $this->assertRegExp($base64pattern, $str);
        $this->assertRegExp($base64pattern, $str2);
        if ($minLength !== null) {
            $this->assertGreaterThanOrEqual($minLength, mb_strlen($str));
            $this->assertGreaterThanOrEqual($minLength, mb_strlen($str2));
        }
        if ($maxLength !== null) {
            $this->assertLessThanOrEqual($maxLength, mb_strlen($str));
            $this->assertLessThanOrEqual($maxLength, mb_strlen($str2));
        }
    }

    public function provideMockStringByteFormatArguments()
    {
        return [
            [IMocker::DATA_FORMAT_BYTE, null, null],
            [IMocker::DATA_FORMAT_BYTE, 10, null],
            [IMocker::DATA_FORMAT_BYTE, 10, 10],
            [IMocker::DATA_FORMAT_BYTE, null, 12],
        ];
    }

    /**
     * @covers ::mock
     * @covers ::mockString
     * @dataProvider provideMockStringBinaryFormatArguments
     */
    public function testMockStringWithBinaryFormat(
        $dataFormat,
        $minLength,
        $maxLength
    ) {
        $mocker = new OpenApiDataMocker();
        $str = $mocker->mockString($dataFormat, $minLength, $maxLength);
        $str2 = $mocker->mock(IMocker::DATA_TYPE_STRING, $dataFormat, ['minLength' => $minLength, 'maxLength' => $maxLength]);
        if ($minLength !== null) {
            $this->assertGreaterThanOrEqual($minLength, strlen($str));
            $this->assertGreaterThanOrEqual($minLength, strlen($str2));
        }
        if ($maxLength !== null) {
            $this->assertLessThanOrEqual($maxLength, strlen($str));
            $this->assertLessThanOrEqual($maxLength, strlen($str2));
        }
    }

    public function provideMockStringBinaryFormatArguments()
    {
        return [
            [IMocker::DATA_FORMAT_BINARY, 0, null],
            [IMocker::DATA_FORMAT_BINARY, 10, null],
            [IMocker::DATA_FORMAT_BINARY, 0, 100],
            [IMocker::DATA_FORMAT_BINARY, 10, 50],
            [IMocker::DATA_FORMAT_BINARY, 10, 10],
            [IMocker::DATA_FORMAT_BINARY, 0, 0],
        ];
    }

    /**
     * @covers ::mock
     * @covers ::mockString
     * @dataProvider provideMockStringDateFormatArguments
     */
    public function testMockStringWithDateAndDateTimeFormat(
        $dataFormat,
        $minLength,
        $maxLength,
        $dtFormat
    ) {
        $mocker = new OpenApiDataMocker();
        $str = $mocker->mockString($dataFormat, $minLength, $maxLength);
        $str2 = $mocker->mock(IMocker::DATA_TYPE_STRING, $dataFormat, ['minLength' => $minLength, 'maxLength' => $maxLength]);

        if ($dtFormat !== null) {
            $date = DateTime::createFromFormat($dtFormat, $str);
            $date2 = DateTime::createFromFormat($dtFormat, $str2);
            $this->assertInstanceOf(DateTime::class, $date);
            $this->assertInstanceOf(DateTime::class, $date2);
        }
        if ($minLength !== null) {
            $this->assertGreaterThanOrEqual($minLength, mb_strlen($str));
            $this->assertGreaterThanOrEqual($minLength, mb_strlen($str2));
        }
        if ($maxLength !== null) {
            $this->assertLessThanOrEqual($maxLength, mb_strlen($str));
            $this->assertLessThanOrEqual($maxLength, mb_strlen($str2));
        }
    }

    public function provideMockStringDateFormatArguments()
    {
        return [
            [IMocker::DATA_FORMAT_DATE, null, null, 'Y-m-d'],
            [IMocker::DATA_FORMAT_DATE, 10, null, 'Y-m-d'],
            [IMocker::DATA_FORMAT_DATE, 10, 10, 'Y-m-d'],
            [IMocker::DATA_FORMAT_DATE, null, 8, null],
            [IMocker::DATA_FORMAT_DATE, 16, null, null],
            [IMocker::DATA_FORMAT_DATE_TIME, null, null, 'Y-m-d\TH:i:sP'],
            [IMocker::DATA_FORMAT_DATE_TIME, 25, null, 'Y-m-d\TH:i:sP'],
            [IMocker::DATA_FORMAT_DATE_TIME, 25, 25, 'Y-m-d\TH:i:sP'],
            [IMocker::DATA_FORMAT_DATE_TIME, null, 20, null],
            [IMocker::DATA_FORMAT_DATE_TIME, 30, null, null],
        ];
    }

    /**
     * @covers ::mock
     * @covers ::mockString
     * @dataProvider provideMockStringUuidFormatArguments
     */
    public function testMockStringWithUuidFormat(
        $minLength,
        $maxLength
    ) {
        $mocker = new OpenApiDataMocker();
        $arr = [];
        $arr2 = [];
        $hexPattern = '/^[a-f0-9]*$/';

        while (count($arr) < 100 && count($arr2) < 100) {
            $str = $mocker->mockString(IMocker::DATA_FORMAT_UUID, $minLength, $maxLength);
            $str2 = $mocker->mock(IMocker::DATA_TYPE_STRING, IMocker::DATA_FORMAT_UUID, ['minLength' => $minLength, 'maxLength' => $maxLength]);
            $arr[] = $str;
            $arr2[] = $str2;

            $this->assertRegExp($hexPattern, $str);
            $this->assertRegExp($hexPattern, $str2);

            if ($minLength !== null) {
                $this->assertGreaterThanOrEqual($minLength, mb_strlen($str));
                $this->assertGreaterThanOrEqual($minLength, mb_strlen($str2));
            }
            if ($maxLength !== null) {
                $this->assertLessThanOrEqual($maxLength, mb_strlen($str));
                $this->assertLessThanOrEqual($maxLength, mb_strlen($str2));
            }
        }
    }

    public function provideMockStringUuidFormatArguments()
    {
        return [
            [null, null],
            [10, null],
            [10, 10],
            [null, 8],
            [16, null],
            [null, null],
            [25, null],
            [25, 25],
            [null, 20],
            [30, null],
            [1, 1],
        ];
    }

    /**
     * @covers ::mockBoolean
     */
    public function testMockBoolean()
    {
        $mocker = new OpenApiDataMocker();
        $bool = $mocker->mockBoolean();

        $matchingInternalTypes = [
            IsType::TYPE_SCALAR,
            IsType::TYPE_BOOL,
        ];

        foreach ($matchingInternalTypes as $matchType) {
            $this->assertInternalType($matchType, $bool);
        }

        $notMatchingInternalTypes = [
            IsType::TYPE_NUMERIC,
            IsType::TYPE_FLOAT,
            IsType::TYPE_INT,
            IsType::TYPE_ARRAY,
            IsType::TYPE_STRING,
            IsType::TYPE_NULL,
            IsType::TYPE_OBJECT,
            IsType::TYPE_RESOURCE,
            IsType::TYPE_CALLABLE,
        ];

        foreach ($notMatchingInternalTypes as $notMatchType) {
            $this->assertNotInternalType($notMatchType, $bool);
        }
    }

    private function internalAssertNumber(
        $number,
        $minimum = null,
        $maximum = null,
        $exclusiveMinimum = false,
        $exclusiveMaximum = false,
        $matchingInternalTypes = [],
        $notMatchingInternalTypes = []
    ) {
        foreach ($matchingInternalTypes as $matchType) {
            $this->assertInternalType($matchType, $number);
        }

        foreach ($notMatchingInternalTypes as $notMatchType) {
            $this->assertNotInternalType($notMatchType, $number);
        }

        if ($minimum !== null) {
            if ($exclusiveMinimum) {
                $this->assertGreaterThan($minimum, $number);
            } else {
                $this->assertGreaterThanOrEqual($minimum, $number);
            }
        }

        if ($maximum !== null) {
            if ($exclusiveMaximum) {
                $this->assertLessThan($maximum, $number);
            } else {
                $this->assertLessThanOrEqual($maximum, $number);
            }
        }
    }

    private function internalAssertString(
        $str,
        $minLength = null,
        $maxLength = null,
        $enum = null,
        $matchingInternalTypes = [],
        $notMatchingInternalTypes = []
    ) {
        foreach ($matchingInternalTypes as $matchType) {
            $this->assertInternalType($matchType, $str);
        }

        foreach ($notMatchingInternalTypes as $notMatchType) {
            $this->assertNotInternalType($notMatchType, $str);
        }

        if ($minLength !== null) {
            $this->assertGreaterThanOrEqual($minLength, mb_strlen($str, 'UTF-8'));
        }

        if ($maxLength !== null) {
            $this->assertLessThanOrEqual($maxLength, mb_strlen($str, 'UTF-8'));
        }

        if (is_array($enum) && !empty($enum)) {
            $this->assertContains($str, $enum);
        }
    }

    /**
     * @dataProvider provideMockArrayCorrectArguments
     * @covers ::mockArray
     */
    public function testMockArrayFlattenWithCorrectArguments(
        $items,
        $minItems,
        $maxItems,
        $uniqueItems,
        $expectedItemsType = null,
        $expectedArraySize = null
    ) {
        $mocker = new OpenApiDataMocker();
        $arr = $mocker->mockArray($items, $minItems, $maxItems, $uniqueItems);

        $this->assertIsArray($arr);
        if ($expectedArraySize !== null) {
            $this->assertCount($expectedArraySize, $arr);
        }
        if ($expectedItemsType && $expectedArraySize > 0) {
            $this->assertContainsOnly($expectedItemsType, $arr, true);
        }

        if (is_array($items)) {
            $dataType = $items['type'];
            $dataFormat = $items['dataFormat'] ?? null;

            // items field numeric properties
            $minimum = $items['minimum'] ?? null;
            $maximum = $items['maximum'] ?? null;
            $exclusiveMinimum = $items['exclusiveMinimum'] ?? null;
            $exclusiveMaximum = $items['exclusiveMaximum'] ?? null;

            // items field string properties
            $minLength = $items['minLength'] ?? null;
            $maxLength = $items['maxLength'] ?? null;
            $enum = $items['enum'] ?? null;
            $pattern = $items['pattern'] ?? null;

            // items field array properties
            $subItems = $items['items'] ?? null;
            $subMinItems = $items['minItems'] ?? null;
            $subMaxItems = $items['maxItems'] ?? null;
            $subUniqueItems = $items['uniqueItems'] ?? null;
        } else {
            // is object
            $dataType = $items->type;
            $dataFormat = $items->dataFormat ?? null;

            // items field numeric properties
            $minimum = $items->minimum ?? null;
            $maximum = $items->maximum ?? null;
            $exclusiveMinimum = $items->exclusiveMinimum ?? null;
            $exclusiveMaximum = $items->exclusiveMaximum ?? null;

            // items field string properties
            $minLength = $items->minLength ?? null;
            $maxLength = $items->maxLength ?? null;
            $enum = $items->enum ?? null;
            $pattern = $items->pattern ?? null;

            // items field array properties
            $subItems = $items->items ?? null;
            $subMinItems = $items->minItems ?? null;
            $subMaxItems = $items->maxItems ?? null;
            $subUniqueItems = $items->uniqueItems ?? null;
        }


        foreach ($arr as $item) {
            switch ($dataType) {
                case IMocker::DATA_TYPE_INTEGER:
                    $this->internalAssertNumber($item, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);
                    break;
                case IMocker::DATA_TYPE_NUMBER:
                    $this->internalAssertNumber($item, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);
                    break;
                case IMocker::DATA_TYPE_STRING:
                    $this->internalAssertString($item, $minLength, $maxLength);
                    break;
                case IMocker::DATA_TYPE_BOOLEAN:
                    $this->assertInternalType(IsType::TYPE_BOOL, $item);
                    break;
                case IMocker::DATA_TYPE_ARRAY:
                    $this->testMockArrayFlattenWithCorrectArguments($subItems, $subMinItems, $subMaxItems, $subUniqueItems);
                    break;
            }
        }
    }

    public function provideMockArrayCorrectArguments()
    {
        $intItems = ['type' => IMocker::DATA_TYPE_INTEGER, 'minimum' => 5, 'maximum' => 10];
        $floatItems = ['type' => IMocker::DATA_TYPE_NUMBER, 'minimum' => -32.4, 'maximum' => 88.6, 'exclusiveMinimum' => true, 'exclusiveMaximum' => true];
        $strItems = ['type' => IMocker::DATA_TYPE_STRING, 'minLength' => 20, 'maxLength' => 50];
        $boolItems = (object) ['type' => IMocker::DATA_TYPE_BOOLEAN];
        $arrayItems = (object) ['type' => IMocker::DATA_TYPE_ARRAY, 'items' => ['type' => IMocker::DATA_TYPE_STRING, 'minItems' => 3, 'maxItems' => 10]];
        $objectItems = (object) ['type' => IMocker::DATA_TYPE_OBJECT, 'properties' => (object)['username' => ['type' => IMocker::DATA_TYPE_STRING]]];
        $expectedInt = IsType::TYPE_INT;
        $expectedFloat = IsType::TYPE_FLOAT;
        $expectedStr = IsType::TYPE_STRING;
        $expectedBool = IsType::TYPE_BOOL;
        $expectedArray = IsType::TYPE_ARRAY;
        $expectedObject = IsType::TYPE_OBJECT;

        return [
            'empty array' => [
                $strItems, null, 0, false, null, 0,
            ],
            'empty array, limit zero' => [
                $strItems, 0, 0, false, null, 0,
            ],
            'array of one string as default size' => [
                $strItems, null, null, false, $expectedStr, 1,
            ],
            'array of one string, limit one' => [
                $strItems, 1, 1, false, $expectedStr, 1,
            ],
            'array of two strings' => [
                $strItems, 2, null, false, $expectedStr, 2,
            ],
            'array of five strings, limit ten' => [
                $strItems, 5, 10, false, $expectedStr, 5,
            ],
            'array of five strings, limit five' => [
                $strItems, 5, 5, false, $expectedStr, 5,
            ],
            'array of one string, limit five' => [
                $strItems, null, 5, false, $expectedStr, 1,
            ],
            'array of one integer' => [
                $intItems, null, null, false, $expectedInt, 1,
            ],
            'array of one float' => [
                $floatItems, null, null, false, $expectedFloat, 1,
            ],
            'array of one boolean' => [
                $boolItems, null, null, false, $expectedBool, 1,
            ],
            'array of one array of strings' => [
                $arrayItems, null, null, false, $expectedArray, 1,
            ],
            'array of one object' => [
                $objectItems, null, null, false, $expectedObject, 1
            ],
        ];
    }

    /**
     * @dataProvider provideMockArrayInvalidArguments
     * @expectedException \InvalidArgumentException
     * @covers ::mockArray
     */
    public function testMockArrayWithInvalidArguments(
        $items,
        $minItems,
        $maxItems,
        $uniqueItems
    ) {
        $mocker = new OpenApiDataMocker();
        $arr = $mocker->mockArray($items, $minItems, $maxItems, $uniqueItems);
    }

    public function provideMockArrayInvalidArguments()
    {
        $intItems = ['type' => IMocker::DATA_TYPE_INTEGER];

        return [
            'items is nor array' => [
                'foobar', null, null, false,
            ],
            'items doesnt have "type" key' => [
                ['foobar' => 'foobaz'], null, null, false,
            ],
            'minItems is not integer' => [
                $intItems, 3.12, null, false,
            ],
            'minItems is negative' => [
                $intItems, -10, null, false,
            ],
            'minItems is not number' => [
                $intItems, '1', null, false,
            ],
            'maxItems is not integer' => [
                $intItems, null, 3.12, false,
            ],
            'maxItems is negative' => [
                $intItems, null, -10, false,
            ],
            'maxItems is not number' => [
                $intItems, null, 'foobaz', false,
            ],
            'maxItems less than minItems' => [
                $intItems, 5, 2, false,
            ],
            'items with ref to unknown class' => [
                ['$ref' => '#/components/schemas/UnknownClass'], null, null, false,
            ],
            'items with ref to class without getOpenApiSchema method' => [
                ['$ref' => '#/components/schemas/ClassWithoutGetSchemaMethod'], null, null, false,
            ],
        ];
    }

    /**
     * @dataProvider provideMockArrayWithRefArguments
     * @covers ::mockArray
     */
    public function testMockArrayWithRef($items, $expectedStructure)
    {
        $mocker = new OpenApiDataMocker();
        $arr = $mocker->mockArray($items);
        $this->assertIsArray($arr);
        $this->assertCount(1, $arr);
        foreach ($arr as $item) {
            // TODO: replace with assertInstanceOf assertion
            $this->assertInternalType(IsType::TYPE_OBJECT, $item);
            foreach ($expectedStructure as $expectedProp => $expectedType) {
                $this->assertInternalType($expectedType, $item->$expectedProp);
            }
        }
    }

    public function provideMockArrayWithRefArguments()
    {
        return [
            'items with ref to CatRefTestClass' => [
                ['$ref' => '#/components/schemas/CatRefTestClass'],
                [
                    'className' => IsType::TYPE_STRING,
                    'color' => IsType::TYPE_STRING,
                    'declawed' => IsType::TYPE_BOOL,
                ],
            ],
        ];
    }

    /**
     * @dataProvider provideMockObjectCorrectArguments
     * @covers ::mockObject
     */
    public function testMockObjectWithCorrectArguments(
        $properties,
        $minProperties,
        $maxProperties,
        $additionalProperties,
        $required,
        $expectedKeys
    ) {
        $mocker = new OpenApiDataMocker();
        $obj = $mocker->mockObject(
            $properties,
            $minProperties,
            $maxProperties,
            $additionalProperties,
            $required
        );

        $this->assertInternalType(IsType::TYPE_OBJECT, $obj);
        $this->assertSame($expectedKeys, array_keys(get_object_vars($obj)));
    }

    public function provideMockObjectCorrectArguments()
    {
        $additionProps = [
            'extra' => [
                'type' => IMocker::DATA_TYPE_STRING,
            ],
        ];
        return [
            'empty object' => [
                [], 1, 10, true, null, [],
            ],
            'empty object from StdClass' => [
                new StdClass(), 1, 5, false, null, [],
            ],
            'object with username property' => [
                [
                    'username' => [
                        'type' => IMocker::DATA_TYPE_STRING,
                    ],
                ], 0, 5, $additionProps, null, ['username'],
            ],
            'object with foobar property' => [
                (object) [
                    'foobar' => [
                        'type' => IMocker::DATA_TYPE_INTEGER,
                    ],
                ], 1, 1, (object) $additionProps, null, ['foobar'],
            ],
        ];
    }

    /**
     * @dataProvider provideMockObjectInvalidArguments
     * @expectedException \InvalidArgumentException
     * @covers ::mockObject
     */
    public function testMockObjectWithInvalidArguments(
        $properties,
        $minProperties,
        $maxProperties,
        $additionalProperties,
        $required
    ) {
        $mocker = new OpenApiDataMocker();
        $obj = $mocker->mockObject($properties, $minProperties, $maxProperties, $additionalProperties, $required);
    }

    public function provideMockObjectInvalidArguments()
    {
        return [
            'properties cannot be null' => [
                null, 0, 10, false, null,
            ],
            'properties cannot be a string' => [
                'foobar', 0, 10, false, null,
            ],
            'property value cannot be a string' => [
                ['username' => 'foobar'], 0, 10, false, null,
            ],
            'minProperties is not integer' => [
                [], 3.12, null, false, null,
            ],
            'minProperties is negative' => [
                [], -10, null, false, null,
            ],
            'minProperties is not number' => [
                [], '1', null, false, null,
            ],
            'maxProperties is not integer' => [
                [], null, 3.12, false, null,
            ],
            'maxProperties is negative' => [
                [], null, -10, false, null,
            ],
            'maxProperties is not number' => [
                [], null, 'foobaz', false, null,
            ],
            'maxProperties less than minProperties' => [
                [], 5, 2, false, null,
            ],
            'additionalProperties is not object|array|boolean' => [
                [], null, null, 'foobar', null,
            ],
            'required is object, not array' => [
                [], null, null, null, new StdClass(),
            ],
            'required is not array' => [
                [], null, null, null, 'foobar',
            ],
            'required array with duplicates' => [
                [], null, null, null, ['username', 'username'],
            ],
            'required array of non-strings' => [
                [], null, null, null, [1, 2, 3],
            ],
        ];
    }

    /**
     * @covers ::mockObject
     */
    public function testMockObjectWithReferencedProps()
    {
        $mocker = new OpenApiDataMocker();
        $obj = $mocker->mockObject(
            (object) [
                'cat' => [
                    '$ref' => '#/components/schemas/CatRefTestClass',
                ],
            ]
        );
        $this->assertInternalType(IsType::TYPE_OBJECT, $obj->cat);
        $this->assertInternalType(IsType::TYPE_STRING, $obj->cat->className);
        $this->assertInternalType(IsType::TYPE_STRING, $obj->cat->color);
        $this->assertInternalType(IsType::TYPE_BOOL, $obj->cat->declawed);
    }

    /**
     * @dataProvider provideMockFromSchemaCorrectArguments
     * @covers ::mockFromSchema
     */
    public function testMockFromSchemaWithCorrectArguments($schema, $expectedType)
    {
        $mocker = new OpenApiDataMocker();
        $data = $mocker->mockFromSchema($schema);
        $this->assertInternalType($expectedType, $data);
    }

    public function provideMockFromSchemaCorrectArguments()
    {
        return [
            'string from object' => [
                (object) ['type' => IMocker::DATA_TYPE_STRING],
                IsType::TYPE_STRING,
            ],
            'string from array' => [
                ['type' => IMocker::DATA_TYPE_STRING],
                IsType::TYPE_STRING,
            ],
            'integer from object' => [
                (object) ['type' => IMocker::DATA_TYPE_INTEGER],
                IsType::TYPE_INT,
            ],
            'integer from array' => [
                ['type' => IMocker::DATA_TYPE_INTEGER],
                IsType::TYPE_INT,
            ],
            'number from object' => [
                (object) ['type' => IMocker::DATA_TYPE_NUMBER],
                IsType::TYPE_FLOAT,
            ],
            'number from array' => [
                ['type' => IMocker::DATA_TYPE_NUMBER],
                IsType::TYPE_FLOAT,
            ],
            'string from object' => [
                (object) ['type' => IMocker::DATA_TYPE_STRING],
                IsType::TYPE_STRING,
            ],
            'string from array' => [
                ['type' => IMocker::DATA_TYPE_STRING],
                IsType::TYPE_STRING,
            ],
            'boolean from object' => [
                (object) ['type' => IMocker::DATA_TYPE_BOOLEAN],
                IsType::TYPE_BOOL,
            ],
            'boolean from array' => [
                ['type' => IMocker::DATA_TYPE_BOOLEAN],
                IsType::TYPE_BOOL,
            ],
            'array of strings from object' => [
                (object) [
                    'type' => IMocker::DATA_TYPE_ARRAY,
                    'items' => ['type' => IMocker::DATA_TYPE_STRING],
                ],
                IsType::TYPE_ARRAY,
            ],
            'array of strings from array' => [
                [
                    'type' => IMocker::DATA_TYPE_ARRAY,
                    'items' => ['type' => IMocker::DATA_TYPE_STRING],
                ],
                IsType::TYPE_ARRAY,
            ],
            'object with username prop from object' => [
                (object) [
                    'type' => IMocker::DATA_TYPE_OBJECT,
                    'properties' => ['username' => ['type' => IMocker::DATA_TYPE_STRING]],
                ],
                IsType::TYPE_OBJECT,
            ],
            'object with username prop from array' => [
                [
                    'type' => IMocker::DATA_TYPE_OBJECT,
                    'properties' => ['username' => ['type' => IMocker::DATA_TYPE_STRING]],
                ],
                IsType::TYPE_OBJECT,
            ],
            'referenced class' => [
                ['$ref' => '#/components/schemas/CatRefTestClass'],
                IsType::TYPE_OBJECT,
            ],
        ];
    }

    /**
     * @dataProvider provideMockFromSchemaInvalidArguments
     * @expectedException \InvalidArgumentException
     * @covers ::mockFromSchema
     */
    public function testMockFromSchemaWithInvalidArguments($schema)
    {
        $mocker = new OpenApiDataMocker();
        $data = $mocker->mockFromSchema($schema);
    }


    public function provideMockFromSchemaInvalidArguments()
    {
        return [
            'null' => [null],
            'numeric' => [3.14],
            'empty array' => [[]],
            'empty object' => [(object) []],
            'string' => ['foobar'],
            'DateTime object' => [new DateTime()],
        ];
    }

    /**
     * @dataProvider provideMockFromRefCorrectArguments
     * @covers ::mockFromRef
     */
    public function testMockFromRefWithCorrectArguments($ref, $expectedStructure)
    {
        $mocker = new OpenApiDataMocker();
        $data = $mocker->mockFromRef($ref);
        foreach ($expectedStructure as $expectedProp => $expectedType) {
            $this->assertInternalType($expectedType, $data->$expectedProp);
        }
    }

    public function provideMockFromRefCorrectArguments()
    {
        return [
            'CatRefTestClass model' => [
                '#/components/schemas/CatRefTestClass',
                [
                    'className' => IsType::TYPE_STRING,
                    'color' => IsType::TYPE_STRING,
                    'declawed' => IsType::TYPE_BOOL,
                ]
            ],
        ];
    }

    /**
     * @dataProvider provideMockFromRefInvalidArguments
     * @expectedException \InvalidArgumentException
     * @covers ::mockFromRef
     */
    public function testMockFromRefWithInvalidArguments($ref)
    {
        $mocker = new OpenApiDataMocker();
        $data = $mocker->mockFromRef($ref);
    }

    public function provideMockFromRefInvalidArguments()
    {
        return [
            'ref to unknown class' => ['#/components/schemas/UnknownClass'],
            'ref to class without getOpenApiSchema method' => ['#/components/schemas/ClassWithoutGetSchemaMethod'],
        ];
    }
}

namespace {{modelPackage}};

// phpcs:disable PSR1.Classes.ClassDeclaration.MultipleClasses
final class CatRefTestClass
{
    private const MODEL_SCHEMA = <<<'SCHEMA'
{
    "required" : [ "className" ],
    "type" : "object",
    "properties" : {
        "className" : {
            "type" : "string"
        },
        "color" : {
            "type" : "string",
            "default" : "red"
        },
        "declawed" : {
            "type" : "boolean"
        }
    },
    "discriminator" : {
        "propertyName" : "className"
    }
}
SCHEMA;

    public static function getOpenApiSchema()
    {
        return json_decode(static::MODEL_SCHEMA, true);
    }
}

final class ClassWithoutGetSchemaMethod
{
}
{{/apiInfo}}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy