[Slim4] Data mocker for scalar types (#4751)

* [Slim4] Add OpenApiDataMocker interface template

* [Slim4] Implement scalar types in data mocker

* [Slim4] Cleanup, remove unused variables

I've rejected the idea to keep Composer dependencies in Java/codegen
variables at some point of time. It seems that after Git rebase I forgot
to delete them.

* [Slim4] Refresh samples

* [Slim4] Add pattern option to mockString method

[ref] https://tools.ietf.org/html/draft-wright-json-schema-validation-00#section-5.8

* [Slim4] Add enum option to mockString method

[ref] https://tools.ietf.org/html/draft-wright-json-schema-validation-00#section-5.20

* [Slim4] Refactor mockInteger and mockNumber tests

* [Slim4] Refactor mockString tests

* [Slim4] Use null coalescing operator

* [Slim4] Implement enum option in mockString method

* [Slim4] Add tests for enum option of mockString
This commit is contained in:
Yuriy Belenko 2019-12-16 14:32:07 +05:00 committed by William Cheng
parent adbed055dd
commit 7bd378c026
11 changed files with 1763 additions and 4 deletions

View File

@ -40,8 +40,8 @@ public class PhpSlim4ServerCodegen extends PhpSlimServerCodegen {
public static final String PSR7_IMPLEMENTATION = "psr7Implementation"; public static final String PSR7_IMPLEMENTATION = "psr7Implementation";
protected String psr7Implementation = "slim-psr7"; protected String psr7Implementation = "slim-psr7";
protected List<Map<String, String>> composerPackages = new ArrayList<Map<String, String>>(); protected String mockDirName = "Mock";
protected List<Map<String, String>> composerDevPackages = new ArrayList<Map<String, String>>(); protected String mockPackage = "";
public PhpSlim4ServerCodegen() { public PhpSlim4ServerCodegen() {
super(); super();
@ -50,6 +50,7 @@ public class PhpSlim4ServerCodegen extends PhpSlimServerCodegen {
.stability(Stability.STABLE) .stability(Stability.STABLE)
.build(); .build();
mockPackage = invokerPackage + "\\" + mockDirName;
outputFolder = "generated-code" + File.separator + "slim4"; outputFolder = "generated-code" + File.separator + "slim4";
embeddedTemplateDir = templateDir = "php-slim4-server"; embeddedTemplateDir = templateDir = "php-slim4-server";
@ -84,6 +85,16 @@ public class PhpSlim4ServerCodegen extends PhpSlimServerCodegen {
public void processOpts() { public void processOpts() {
super.processOpts(); super.processOpts();
if (additionalProperties.containsKey(CodegenConstants.INVOKER_PACKAGE)) {
// Update the invokerPackage for the default mockPackage
mockPackage = invokerPackage + "\\" + mockDirName;
}
// make mock src path available in mustache template
additionalProperties.put("mockPackage", mockPackage);
additionalProperties.put("mockSrcPath", "./" + toSrcPath(mockPackage, srcBasePath));
additionalProperties.put("mockTestPath", "./" + toSrcPath(mockPackage, testBasePath));
if (additionalProperties.containsKey(PSR7_IMPLEMENTATION)) { if (additionalProperties.containsKey(PSR7_IMPLEMENTATION)) {
this.setPsr7Implementation((String) additionalProperties.get(PSR7_IMPLEMENTATION)); this.setPsr7Implementation((String) additionalProperties.get(PSR7_IMPLEMENTATION));
} }
@ -116,6 +127,11 @@ public class PhpSlim4ServerCodegen extends PhpSlimServerCodegen {
// Slim 4 doesn't parse JSON body anymore we need to add suggested middleware // Slim 4 doesn't parse JSON body anymore we need to add suggested middleware
// ref: https://www.slimframework.com/docs/v4/objects/request.html#the-request-body // ref: https://www.slimframework.com/docs/v4/objects/request.html#the-request-body
supportingFiles.add(new SupportingFile("json_body_parser_middleware.mustache", toSrcPath(invokerPackage + "\\Middleware", srcBasePath), "JsonBodyParserMiddleware.php")); supportingFiles.add(new SupportingFile("json_body_parser_middleware.mustache", toSrcPath(invokerPackage + "\\Middleware", srcBasePath), "JsonBodyParserMiddleware.php"));
// mocking feature
supportingFiles.add(new SupportingFile("openapi_data_mocker_interface.mustache", toSrcPath(mockPackage, srcBasePath), toInterfaceName("OpenApiDataMocker") + ".php"));
supportingFiles.add(new SupportingFile("openapi_data_mocker.mustache", toSrcPath(mockPackage, srcBasePath), "OpenApiDataMocker.php"));
supportingFiles.add(new SupportingFile("openapi_data_mocker_test.mustache", toSrcPath(mockPackage, testBasePath), "OpenApiDataMockerTest.php"));
} }
/** /**

View File

@ -42,10 +42,12 @@
"scripts": { "scripts": {
"test": [ "test": [
"@test-apis", "@test-apis",
"@test-models" "@test-models",
"@test-mock"
], ],
"test-apis": "phpunit --testsuite Apis", "test-apis": "phpunit --testsuite Apis",
"test-models": "phpunit --testsuite Models", "test-models": "phpunit --testsuite Models",
"test-mock": "phpunit --testsuite Mock",
"phpcs": "phpcs", "phpcs": "phpcs",
"phplint": "phplint ./ --exclude=vendor" "phplint": "phplint ./ --exclude=vendor"
} }

View File

@ -0,0 +1,269 @@
<?php
/**
* OpenApiDataMocker
*
* PHP version 7.1
*
* @package {{invokerPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**{{#apiInfo}}{{#appName}}
* {{{appName}}}
*
{{/appName}}
{{#appDescription}}
* {{{appDescription}}}
{{/appDescription}}
{{#version}}
* The version of the OpenAPI document: {{{version}}}
{{/version}}
{{#infoEmail}}
* Contact: {{{infoEmail}}}
{{/infoEmail}}
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace {{mockPackage}};
use {{mockPackage}}\{{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}} as IMocker;
use InvalidArgumentException;
/**
* OpenApiDataMocker Class Doc Comment
*
* @package {{mockPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
final class OpenApiDataMocker implements IMocker
{
/**
* Mocks OpenApi Data.
* @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types
*
* @param $dataType string OpenApi data type. Use constants from {{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}} class
* @param $dataFormat string (optional) OpenApi data format
* @param $options array|null (optional) OpenApi data options
*
* @throws \InvalidArgumentException when invalid arguments passed
*
* @return mixed
*/
public function mock($dataType, $dataFormat = null, $options = [])
{
switch ($dataType) {
case IMocker::DATA_TYPE_INTEGER:
case IMocker::DATA_TYPE_NUMBER:
$minimum = $options['minimum'] ?? null;
$maximum = $options['maximum'] ?? null;
$exclusiveMinimum = $options['exclusiveMinimum'] ?? false;
$exclusiveMaximum = $options['exclusiveMaximum'] ?? false;
if ($dataType === IMocker::DATA_TYPE_INTEGER) {
return $this->mockInteger($dataFormat, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);
}
return $this->mockNumber($dataFormat, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);
case IMocker::DATA_TYPE_STRING:
$minLength = $options['minLength'] ?? 0;
$maxLength = $options['maxLength'] ?? null;
return $this->mockString($dataFormat, $minLength, $maxLength);
case IMocker::DATA_TYPE_BOOLEAN:
return $this->mockBoolean();
default:
throw new InvalidArgumentException('"dataType" must be one of ' . implode(', ', [
IMocker::DATA_TYPE_INTEGER,
IMocker::DATA_TYPE_NUMBER,
IMocker::DATA_TYPE_STRING,
IMocker::DATA_TYPE_BOOLEAN,
]));
}
}
/**
* Shortcut to mock integer type
* Equivalent to mockData(DATA_TYPE_INTEGER);
*
* @param string|null $dataFormat (optional) int32 or int64
* @param number|null $minimum (optional) Default is 0
* @param number|null $maximum (optional) Default is mt_getrandmax()
* @param bool|null $exclusiveMinimum (optional) Default is false
* @param bool|null $exclusiveMaximum (optional) Default is false
*
* @throws \InvalidArgumentException when $maximum less than $minimum or invalid arguments provided
*
* @return int
*/
public function mockInteger(
$dataFormat = null,
$minimum = null,
$maximum = null,
$exclusiveMinimum = false,
$exclusiveMaximum = false
) {
return $this->getRandomNumber($minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum, 0);
}
/**
* Shortcut to mock number type
* Equivalent to mockData(DATA_TYPE_NUMBER);
*
* @param string|null $dataFormat (optional) float or double
* @param number|null $minimum (optional) Default is 0
* @param number|null $maximum (optional) Default is mt_getrandmax()
* @param bool|null $exclusiveMinimum (optional) Default is false
* @param bool|null $exclusiveMaximum (optional) Default is false
*
* @throws \InvalidArgumentException when $maximum less than $minimum or invalid arguments provided
*
* @return float
*/
public function mockNumber(
$dataFormat = null,
$minimum = null,
$maximum = null,
$exclusiveMinimum = false,
$exclusiveMaximum = false
) {
return $this->getRandomNumber($minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum, 4);
}
/**
* Shortcut to mock string type
* Equivalent to mockData(DATA_TYPE_STRING);
*
* @param string|null $dataFormat (optional) one of byte, binary, date, date-time, password
* @param int|null $minLength (optional) Default is 0
* @param int|null $maxLength (optional) Default is 100 chars
* @param array $enum (optional) This array should have at least one element.
* Elements in the array should be unique.
* @param string|null $pattern (optional) This string should be a valid regular expression, according to the ECMA 262 regular expression dialect.
* Recall: regular expressions are not implicitly anchored.
*
* @throws \InvalidArgumentException when invalid arguments passed
*
* @return string
*/
public function mockString(
$dataFormat = null,
$minLength = 0,
$maxLength = null,
$enum = null,
$pattern = null
) {
if ($enum !== null) {
if (
is_array($enum) === false
|| empty($enum)
|| count($enum) > count(array_unique($enum))
) {
throw new InvalidArgumentException('"enum" must be an array. This array should have at least one element. Elements in the array should be unique.');
}
// return random variant
return $enum[mt_rand(0, count($enum) - 1)];
}
if ($minLength !== 0 && $minLength !== null) {
if (is_int($minLength) === false) {
throw new InvalidArgumentException('"minLength" must be an integer');
} elseif ($minLength < 0) {
throw new InvalidArgumentException('"minLength" must be greater than, or equal to, 0');
}
} else {
$minLength = 0;
}
if ($maxLength !== null) {
if (is_int($maxLength) === false) {
throw new InvalidArgumentException('"maxLength" must be an integer');
} elseif ($maxLength < 0) {
throw new InvalidArgumentException('"maxLength" must be greater than, or equal to, 0');
}
} else {
// since we don't need huge texts by default, lets cut them down to 100 chars
$maxLength = 100;
}
if ($maxLength < $minLength) {
throw new InvalidArgumentException('"maxLength" value cannot be less than "minLength"');
}
return str_pad('', mt_rand($minLength, $maxLength), 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ', \STR_PAD_RIGHT);
}
/**
* Shortcut to mock boolean type
* Equivalent to mockData(DATA_TYPE_BOOLEAN);
*
* @return bool
*/
public function mockBoolean()
{
return (bool) mt_rand(0, 1);
}
/**
* @internal
*
* @return float|int
*/
protected function getRandomNumber(
$minimum = null,
$maximum = null,
$exclusiveMinimum = false,
$exclusiveMaximum = false,
$maxDecimals = 4
) {
$min = 0;
$max = mt_getrandmax();
if ($minimum !== null) {
if (is_numeric($minimum) === false) {
throw new InvalidArgumentException('"minimum" must be a number');
}
$min = $minimum;
}
if ($maximum !== null) {
if (is_numeric($maximum) === false) {
throw new InvalidArgumentException('"maximum" must be a number');
}
$max = $maximum;
}
if ($exclusiveMinimum !== false) {
if (is_bool($exclusiveMinimum) === false) {
throw new InvalidArgumentException('"exclusiveMinimum" must be a boolean');
} elseif ($minimum === null) {
throw new InvalidArgumentException('If "exclusiveMinimum" is present, "minimum" must also be present');
}
$min += 1;
}
if ($exclusiveMaximum !== false) {
if (is_bool($exclusiveMaximum) === false) {
throw new InvalidArgumentException('"exclusiveMaximum" must be a boolean');
} elseif ($maximum === null) {
throw new InvalidArgumentException('If "exclusiveMaximum" is present, "maximum" must also be present');
}
$max -= 1;
}
if ($max < $min) {
throw new InvalidArgumentException('"maximum" value cannot be less than "minimum"');
}
if ($maxDecimals > 0) {
return round($min + mt_rand() / mt_getrandmax() * ($max - $min), $maxDecimals);
}
return mt_rand($min, $max);
}
}
{{/apiInfo}}

View File

@ -0,0 +1,190 @@
<?php
/**
* {{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}}
* @ref https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types
*
* PHP version 7.1
*
* @package {{invokerPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**{{#apiInfo}}{{#appName}}
* {{{appName}}}
*
{{/appName}}
{{#appDescription}}
* {{{appDescription}}}
{{/appDescription}}
{{#version}}
* The version of the OpenAPI document: {{{version}}}
{{/version}}
{{#infoEmail}}
* Contact: {{{infoEmail}}}
{{/infoEmail}}
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace {{mockPackage}};
use InvalidArgumentException;
/**
* {{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}} Class Doc Comment
*
* @package {{mockPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
interface {{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}}
{
/** @var string DATA_TYPE_INTEGER */
public const DATA_TYPE_INTEGER = 'integer';
/** @var string DATA_TYPE_NUMBER */
public const DATA_TYPE_NUMBER = 'number';
/** @var string DATA_TYPE_STRING */
public const DATA_TYPE_STRING = 'string';
/** @var string DATA_TYPE_BOOLEAN */
public const DATA_TYPE_BOOLEAN = 'boolean';
/** @var string DATA_TYPE_FILE */
public const DATA_TYPE_FILE = 'file';
/** @var string DATA_FORMAT_INT32 Signed 32 bits */
public const DATA_FORMAT_INT32 = 'int32';
/** @var string DATA_FORMAT_INT64 Signed 64 bits */
public const DATA_FORMAT_INT64 = 'int64';
/** @var string DATA_FORMAT_FLOAT */
public const DATA_FORMAT_FLOAT = 'float';
/** @var string DATA_FORMAT_DOUBLE */
public const DATA_FORMAT_DOUBLE = 'double';
/** @var string DATA_FORMAT_BYTE base64 encoded characters */
public const DATA_FORMAT_BYTE = 'byte';
/** @var string DATA_FORMAT_BINARY Any sequence of octets */
public const DATA_FORMAT_BINARY = 'binary';
/** @var string DATA_FORMAT_DATE As defined by full-date [RFC3339](http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14) */
public const DATA_FORMAT_DATE = 'date';
/** @var string DATA_FORMAT_DATE_TIME As defined by date-time [RFC3339](http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14) */
public const DATA_FORMAT_DATE_TIME = 'date-time';
/** @var string DATA_FORMAT_PASSWORD Used to hint UIs the input needs to be obscured. */
public const DATA_FORMAT_PASSWORD = 'password';
/** @var string DATA_FORMAT_EMAIL */
public const DATA_FORMAT_EMAIL = 'email';
/** @var string DATA_FORMAT_UUID */
public const DATA_FORMAT_UUID = 'uuid';
/**
* Mocks OpenApi Data.
* @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types
*
* @param $dataType string OpenApi data type. Use constants from this class
* @param $dataFormat string (optional) OpenApi data format
* @param $options array|null (optional) OpenApi data options
*
* @throws \InvalidArgumentException when invalid arguments passed
*
* @return mixed
*/
public function mock(
$dataType,
$dataFormat = null,
$options = []
);
/**
* Shortcut to mock integer type
* Equivalent to mockData(DATA_TYPE_INTEGER);
*
* @param string|null $dataFormat (optional) int32 or int64
* @param number|null $minimum (optional) Default is 0
* @param number|null $maximum (optional) Default is mt_getrandmax()
* @param bool|null $exclusiveMinimum (optional) Default is false
* @param bool|null $exclusiveMaximum (optional) Default is false
*
* @throws \InvalidArgumentException when $maximum less than $minimum or invalid arguments provided
*
* @return int
*/
public function mockInteger(
$dataFormat = null,
$minimum = null,
$maximum = null,
$exclusiveMinimum = false,
$exclusiveMaximum = false
);
/**
* Shortcut to mock number type
* Equivalent to mockData(DATA_TYPE_NUMBER);
*
* @param string|null $dataFormat (optional) float or double
* @param number|null $minimum (optional) Default is 0
* @param number|null $maximum (optional) Default is mt_getrandmax()
* @param bool|null $exclusiveMinimum (optional) Default is false
* @param bool|null $exclusiveMaximum (optional) Default is false
*
* @throws \InvalidArgumentException when $maximum less than $minimum or invalid arguments provided
*
* @return float
*/
public function mockNumber(
$dataFormat = null,
$minimum = null,
$maximum = null,
$exclusiveMinimum = false,
$exclusiveMaximum = false
);
/**
* Shortcut to mock string type
* Equivalent to mockData(DATA_TYPE_STRING);
*
* @param string|null $dataFormat (optional) one of byte, binary, date, date-time, password
* @param int|null $minLength (optional) Default is 0
* @param int|null $maxLength (optional) Default is 100 chars
* @param array $enum (optional) This array should have at least one element.
* Elements in the array should be unique.
* @param string|null $pattern (optional) This string should be a valid regular expression, according to the ECMA 262 regular expression dialect.
* Recall: regular expressions are not implicitly anchored.
*
* @throws \InvalidArgumentException when invalid arguments passed
*
* @return string
*/
public function mockString(
$dataFormat = null,
$minLength = 0,
$maxLength = null,
$enum = null,
$pattern = null
);
/**
* Shortcut to mock boolean type
* Equivalent to mockData(DATA_TYPE_BOOLEAN);
*
* @return bool
*/
public function mockBoolean();
}
{{/apiInfo}}

View File

@ -0,0 +1,420 @@
<?php
/**
* OpenApiDataMockerTest
*
* PHP version 7.1
*
* @package {{invokerPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**{{#apiInfo}}{{#appName}}
* {{{appName}}}
*
{{/appName}}
{{#appDescription}}
* {{{appDescription}}}
{{/appDescription}}
{{#version}}
* The version of the OpenAPI document: {{{version}}}
{{/version}}
{{#infoEmail}}
* Contact: {{{infoEmail}}}
{{/infoEmail}}
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace {{mockPackage}};
use {{mockPackage}}\OpenApiDataMocker;
use {{mockPackage}}\{{interfaceNamePrefix}}OpenApiDataMocker{{interfaceNameSuffix}} as IMocker;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Constraint\IsType;
/**
* OpenApiDataMockerTest Class Doc Comment
*
* @package {{mockPackage}}
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
* @coversDefaultClass \{{mockPackage}}\OpenApiDataMocker
*/
class OpenApiDataMockerTest extends TestCase
{
/**
* @covers ::mock
* @dataProvider provideMockCorrectArguments
*/
public function testMockCorrectArguments($dataType, $dataFormat, $options, $expectedType)
{
$mocker = new OpenApiDataMocker();
$this->assertInternalType($expectedType, $mocker->mock($dataType));
}
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],
];
}
/**
* @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],
];
}
/**
* @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_NUMERIC,
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],
];
}
/**
* @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 ::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);
}
}
}
{{/apiInfo}}

View File

@ -17,11 +17,15 @@
<testsuite name="Models"> <testsuite name="Models">
<directory>{{modelTestPath}}</directory> <directory>{{modelTestPath}}</directory>
</testsuite> </testsuite>
<testsuite name="Mock">
<directory>{{mockTestPath}}</directory>
</testsuite>
</testsuites> </testsuites>
<filter> <filter>
<whitelist processUncoveredFilesFromWhitelist="true"> <whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">{{apiSrcPath}}</directory> <directory suffix=".php">{{apiSrcPath}}</directory>
<directory suffix=".php">{{modelSrcPath}}</directory> <directory suffix=".php">{{modelSrcPath}}</directory>
<directory suffix=".php">{{mockSrcPath}}</directory>
</whitelist> </whitelist>
</filter> </filter>
<php> <php>

View File

@ -29,10 +29,12 @@
"scripts": { "scripts": {
"test": [ "test": [
"@test-apis", "@test-apis",
"@test-models" "@test-models",
"@test-mock"
], ],
"test-apis": "phpunit --testsuite Apis", "test-apis": "phpunit --testsuite Apis",
"test-models": "phpunit --testsuite Models", "test-models": "phpunit --testsuite Models",
"test-mock": "phpunit --testsuite Mock",
"phpcs": "phpcs", "phpcs": "phpcs",
"phplint": "phplint ./ --exclude=vendor" "phplint": "phplint ./ --exclude=vendor"
} }

View File

@ -0,0 +1,260 @@
<?php
/**
* OpenApiDataMocker
*
* PHP version 7.1
*
* @package OpenAPIServer
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**
* OpenAPI Petstore
*
* This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
* The version of the OpenAPI document: 1.0.0
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace OpenAPIServer\Mock;
use OpenAPIServer\Mock\OpenApiDataMockerInterface as IMocker;
use InvalidArgumentException;
/**
* OpenApiDataMocker Class Doc Comment
*
* @package OpenAPIServer\Mock
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
final class OpenApiDataMocker implements IMocker
{
/**
* Mocks OpenApi Data.
* @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types
*
* @param $dataType string OpenApi data type. Use constants from OpenApiDataMockerInterface class
* @param $dataFormat string (optional) OpenApi data format
* @param $options array|null (optional) OpenApi data options
*
* @throws \InvalidArgumentException when invalid arguments passed
*
* @return mixed
*/
public function mock($dataType, $dataFormat = null, $options = [])
{
switch ($dataType) {
case IMocker::DATA_TYPE_INTEGER:
case IMocker::DATA_TYPE_NUMBER:
$minimum = $options['minimum'] ?? null;
$maximum = $options['maximum'] ?? null;
$exclusiveMinimum = $options['exclusiveMinimum'] ?? false;
$exclusiveMaximum = $options['exclusiveMaximum'] ?? false;
if ($dataType === IMocker::DATA_TYPE_INTEGER) {
return $this->mockInteger($dataFormat, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);
}
return $this->mockNumber($dataFormat, $minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum);
case IMocker::DATA_TYPE_STRING:
$minLength = $options['minLength'] ?? 0;
$maxLength = $options['maxLength'] ?? null;
return $this->mockString($dataFormat, $minLength, $maxLength);
case IMocker::DATA_TYPE_BOOLEAN:
return $this->mockBoolean();
default:
throw new InvalidArgumentException('"dataType" must be one of ' . implode(', ', [
IMocker::DATA_TYPE_INTEGER,
IMocker::DATA_TYPE_NUMBER,
IMocker::DATA_TYPE_STRING,
IMocker::DATA_TYPE_BOOLEAN,
]));
}
}
/**
* Shortcut to mock integer type
* Equivalent to mockData(DATA_TYPE_INTEGER);
*
* @param string|null $dataFormat (optional) int32 or int64
* @param number|null $minimum (optional) Default is 0
* @param number|null $maximum (optional) Default is mt_getrandmax()
* @param bool|null $exclusiveMinimum (optional) Default is false
* @param bool|null $exclusiveMaximum (optional) Default is false
*
* @throws \InvalidArgumentException when $maximum less than $minimum or invalid arguments provided
*
* @return int
*/
public function mockInteger(
$dataFormat = null,
$minimum = null,
$maximum = null,
$exclusiveMinimum = false,
$exclusiveMaximum = false
) {
return $this->getRandomNumber($minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum, 0);
}
/**
* Shortcut to mock number type
* Equivalent to mockData(DATA_TYPE_NUMBER);
*
* @param string|null $dataFormat (optional) float or double
* @param number|null $minimum (optional) Default is 0
* @param number|null $maximum (optional) Default is mt_getrandmax()
* @param bool|null $exclusiveMinimum (optional) Default is false
* @param bool|null $exclusiveMaximum (optional) Default is false
*
* @throws \InvalidArgumentException when $maximum less than $minimum or invalid arguments provided
*
* @return float
*/
public function mockNumber(
$dataFormat = null,
$minimum = null,
$maximum = null,
$exclusiveMinimum = false,
$exclusiveMaximum = false
) {
return $this->getRandomNumber($minimum, $maximum, $exclusiveMinimum, $exclusiveMaximum, 4);
}
/**
* Shortcut to mock string type
* Equivalent to mockData(DATA_TYPE_STRING);
*
* @param string|null $dataFormat (optional) one of byte, binary, date, date-time, password
* @param int|null $minLength (optional) Default is 0
* @param int|null $maxLength (optional) Default is 100 chars
* @param array $enum (optional) This array should have at least one element.
* Elements in the array should be unique.
* @param string|null $pattern (optional) This string should be a valid regular expression, according to the ECMA 262 regular expression dialect.
* Recall: regular expressions are not implicitly anchored.
*
* @throws \InvalidArgumentException when invalid arguments passed
*
* @return string
*/
public function mockString(
$dataFormat = null,
$minLength = 0,
$maxLength = null,
$enum = null,
$pattern = null
) {
if ($enum !== null) {
if (
is_array($enum) === false
|| empty($enum)
|| count($enum) > count(array_unique($enum))
) {
throw new InvalidArgumentException('"enum" must be an array. This array should have at least one element. Elements in the array should be unique.');
}
// return random variant
return $enum[mt_rand(0, count($enum) - 1)];
}
if ($minLength !== 0 && $minLength !== null) {
if (is_int($minLength) === false) {
throw new InvalidArgumentException('"minLength" must be an integer');
} elseif ($minLength < 0) {
throw new InvalidArgumentException('"minLength" must be greater than, or equal to, 0');
}
} else {
$minLength = 0;
}
if ($maxLength !== null) {
if (is_int($maxLength) === false) {
throw new InvalidArgumentException('"maxLength" must be an integer');
} elseif ($maxLength < 0) {
throw new InvalidArgumentException('"maxLength" must be greater than, or equal to, 0');
}
} else {
// since we don't need huge texts by default, lets cut them down to 100 chars
$maxLength = 100;
}
if ($maxLength < $minLength) {
throw new InvalidArgumentException('"maxLength" value cannot be less than "minLength"');
}
return str_pad('', mt_rand($minLength, $maxLength), 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. ', \STR_PAD_RIGHT);
}
/**
* Shortcut to mock boolean type
* Equivalent to mockData(DATA_TYPE_BOOLEAN);
*
* @return bool
*/
public function mockBoolean()
{
return (bool) mt_rand(0, 1);
}
/**
* @internal
*
* @return float|int
*/
protected function getRandomNumber(
$minimum = null,
$maximum = null,
$exclusiveMinimum = false,
$exclusiveMaximum = false,
$maxDecimals = 4
) {
$min = 0;
$max = mt_getrandmax();
if ($minimum !== null) {
if (is_numeric($minimum) === false) {
throw new InvalidArgumentException('"minimum" must be a number');
}
$min = $minimum;
}
if ($maximum !== null) {
if (is_numeric($maximum) === false) {
throw new InvalidArgumentException('"maximum" must be a number');
}
$max = $maximum;
}
if ($exclusiveMinimum !== false) {
if (is_bool($exclusiveMinimum) === false) {
throw new InvalidArgumentException('"exclusiveMinimum" must be a boolean');
} elseif ($minimum === null) {
throw new InvalidArgumentException('If "exclusiveMinimum" is present, "minimum" must also be present');
}
$min += 1;
}
if ($exclusiveMaximum !== false) {
if (is_bool($exclusiveMaximum) === false) {
throw new InvalidArgumentException('"exclusiveMaximum" must be a boolean');
} elseif ($maximum === null) {
throw new InvalidArgumentException('If "exclusiveMaximum" is present, "maximum" must also be present');
}
$max -= 1;
}
if ($max < $min) {
throw new InvalidArgumentException('"maximum" value cannot be less than "minimum"');
}
if ($maxDecimals > 0) {
return round($min + mt_rand() / mt_getrandmax() * ($max - $min), $maxDecimals);
}
return mt_rand($min, $max);
}
}

View File

@ -0,0 +1,181 @@
<?php
/**
* OpenApiDataMockerInterface
* @ref https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types
*
* PHP version 7.1
*
* @package OpenAPIServer
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**
* OpenAPI Petstore
*
* This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
* The version of the OpenAPI document: 1.0.0
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace OpenAPIServer\Mock;
use InvalidArgumentException;
/**
* OpenApiDataMockerInterface Class Doc Comment
*
* @package OpenAPIServer\Mock
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
interface OpenApiDataMockerInterface
{
/** @var string DATA_TYPE_INTEGER */
public const DATA_TYPE_INTEGER = 'integer';
/** @var string DATA_TYPE_NUMBER */
public const DATA_TYPE_NUMBER = 'number';
/** @var string DATA_TYPE_STRING */
public const DATA_TYPE_STRING = 'string';
/** @var string DATA_TYPE_BOOLEAN */
public const DATA_TYPE_BOOLEAN = 'boolean';
/** @var string DATA_TYPE_FILE */
public const DATA_TYPE_FILE = 'file';
/** @var string DATA_FORMAT_INT32 Signed 32 bits */
public const DATA_FORMAT_INT32 = 'int32';
/** @var string DATA_FORMAT_INT64 Signed 64 bits */
public const DATA_FORMAT_INT64 = 'int64';
/** @var string DATA_FORMAT_FLOAT */
public const DATA_FORMAT_FLOAT = 'float';
/** @var string DATA_FORMAT_DOUBLE */
public const DATA_FORMAT_DOUBLE = 'double';
/** @var string DATA_FORMAT_BYTE base64 encoded characters */
public const DATA_FORMAT_BYTE = 'byte';
/** @var string DATA_FORMAT_BINARY Any sequence of octets */
public const DATA_FORMAT_BINARY = 'binary';
/** @var string DATA_FORMAT_DATE As defined by full-date [RFC3339](http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14) */
public const DATA_FORMAT_DATE = 'date';
/** @var string DATA_FORMAT_DATE_TIME As defined by date-time [RFC3339](http://xml2rfc.ietf.org/public/rfc/html/rfc3339.html#anchor14) */
public const DATA_FORMAT_DATE_TIME = 'date-time';
/** @var string DATA_FORMAT_PASSWORD Used to hint UIs the input needs to be obscured. */
public const DATA_FORMAT_PASSWORD = 'password';
/** @var string DATA_FORMAT_EMAIL */
public const DATA_FORMAT_EMAIL = 'email';
/** @var string DATA_FORMAT_UUID */
public const DATA_FORMAT_UUID = 'uuid';
/**
* Mocks OpenApi Data.
* @see https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.1.md#data-types
*
* @param $dataType string OpenApi data type. Use constants from this class
* @param $dataFormat string (optional) OpenApi data format
* @param $options array|null (optional) OpenApi data options
*
* @throws \InvalidArgumentException when invalid arguments passed
*
* @return mixed
*/
public function mock(
$dataType,
$dataFormat = null,
$options = []
);
/**
* Shortcut to mock integer type
* Equivalent to mockData(DATA_TYPE_INTEGER);
*
* @param string|null $dataFormat (optional) int32 or int64
* @param number|null $minimum (optional) Default is 0
* @param number|null $maximum (optional) Default is mt_getrandmax()
* @param bool|null $exclusiveMinimum (optional) Default is false
* @param bool|null $exclusiveMaximum (optional) Default is false
*
* @throws \InvalidArgumentException when $maximum less than $minimum or invalid arguments provided
*
* @return int
*/
public function mockInteger(
$dataFormat = null,
$minimum = null,
$maximum = null,
$exclusiveMinimum = false,
$exclusiveMaximum = false
);
/**
* Shortcut to mock number type
* Equivalent to mockData(DATA_TYPE_NUMBER);
*
* @param string|null $dataFormat (optional) float or double
* @param number|null $minimum (optional) Default is 0
* @param number|null $maximum (optional) Default is mt_getrandmax()
* @param bool|null $exclusiveMinimum (optional) Default is false
* @param bool|null $exclusiveMaximum (optional) Default is false
*
* @throws \InvalidArgumentException when $maximum less than $minimum or invalid arguments provided
*
* @return float
*/
public function mockNumber(
$dataFormat = null,
$minimum = null,
$maximum = null,
$exclusiveMinimum = false,
$exclusiveMaximum = false
);
/**
* Shortcut to mock string type
* Equivalent to mockData(DATA_TYPE_STRING);
*
* @param string|null $dataFormat (optional) one of byte, binary, date, date-time, password
* @param int|null $minLength (optional) Default is 0
* @param int|null $maxLength (optional) Default is 100 chars
* @param array $enum (optional) This array should have at least one element.
* Elements in the array should be unique.
* @param string|null $pattern (optional) This string should be a valid regular expression, according to the ECMA 262 regular expression dialect.
* Recall: regular expressions are not implicitly anchored.
*
* @throws \InvalidArgumentException when invalid arguments passed
*
* @return string
*/
public function mockString(
$dataFormat = null,
$minLength = 0,
$maxLength = null,
$enum = null,
$pattern = null
);
/**
* Shortcut to mock boolean type
* Equivalent to mockData(DATA_TYPE_BOOLEAN);
*
* @return bool
*/
public function mockBoolean();
}

View File

@ -17,11 +17,15 @@
<testsuite name="Models"> <testsuite name="Models">
<directory>./test/Model</directory> <directory>./test/Model</directory>
</testsuite> </testsuite>
<testsuite name="Mock">
<directory>./test/Mock</directory>
</testsuite>
</testsuites> </testsuites>
<filter> <filter>
<whitelist processUncoveredFilesFromWhitelist="true"> <whitelist processUncoveredFilesFromWhitelist="true">
<directory suffix=".php">./lib/Api</directory> <directory suffix=".php">./lib/Api</directory>
<directory suffix=".php">./lib/Model</directory> <directory suffix=".php">./lib/Model</directory>
<directory suffix=".php">./lib/Mock</directory>
</whitelist> </whitelist>
</filter> </filter>
<php> <php>

View File

@ -0,0 +1,411 @@
<?php
/**
* OpenApiDataMockerTest
*
* PHP version 7.1
*
* @package OpenAPIServer
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
*/
/**
* OpenAPI Petstore
*
* This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\
* The version of the OpenAPI document: 1.0.0
* Generated by: https://github.com/openapitools/openapi-generator.git
*/
/**
* NOTE: This class is auto generated by the openapi generator program.
* https://github.com/openapitools/openapi-generator
* Do not edit the class manually.
*/
namespace OpenAPIServer\Mock;
use OpenAPIServer\Mock\OpenApiDataMocker;
use OpenAPIServer\Mock\OpenApiDataMockerInterface as IMocker;
use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\Constraint\IsType;
/**
* OpenApiDataMockerTest Class Doc Comment
*
* @package OpenAPIServer\Mock
* @author OpenAPI Generator team
* @link https://github.com/openapitools/openapi-generator
* @coversDefaultClass \OpenAPIServer\Mock\OpenApiDataMocker
*/
class OpenApiDataMockerTest extends TestCase
{
/**
* @covers ::mock
* @dataProvider provideMockCorrectArguments
*/
public function testMockCorrectArguments($dataType, $dataFormat, $options, $expectedType)
{
$mocker = new OpenApiDataMocker();
$this->assertInternalType($expectedType, $mocker->mock($dataType));
}
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],
];
}
/**
* @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],
];
}
/**
* @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_NUMERIC,
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],
];
}
/**
* @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 ::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);
}
}
}