Added tests and fix for issue #1392. Fix regex generated in Ruby client. (#1393)

* Added tests and fix for issue #1392. Param validation with regex not recognizing \d correctly in Ruby client.

* Added generated files to pass ./bin/utils/ensure-up-to-date which is run by circleci
This commit is contained in:
Guy Gershoni
2018-11-07 15:08:23 +11:00
committed by William Cheng
parent f21640f6a1
commit 0e2e1bf715
13 changed files with 340 additions and 13 deletions

View File

@@ -146,6 +146,23 @@ abstract class AbstractRubyCodegen extends DefaultCodegen implements CodegenConf
return name;
}
public String toRegularExpression(String pattern) {
if (StringUtils.isEmpty(pattern)) {
return pattern;
}
// We don't escape \ in string since Ruby doesn't like \ escaped in regex literal
String regexString = pattern;
if (!regexString.startsWith("/")) {
regexString = "/" + regexString;
}
if (StringUtils.countMatches(regexString, '/') == 1) {
// we only have forward slash inserted at start... adding one to end
regexString = regexString + "/";
}
return regexString;
}
@Override
public String toParamName(String name) {
// should be the same as variable name

View File

@@ -13,7 +13,7 @@ GEM
public_suffix (>= 2.0.2, < 4.0)
autotest (4.4.6)
ZenTest (>= 4.4.1)
autotest-fsevent (0.2.13)
autotest-fsevent (0.2.14)
sys-uname
autotest-growl (0.2.16)
autotest-rails-pure (4.1.2)

View File

@@ -300,4 +300,32 @@ public class RubyClientCodegenTest {
CodegenParameter pp = op.pathParams.get(0);
Assert.assertEquals(pp.example, "'orderid123'");
}
/**
* We want to make sure that all Regex patterns:
* - Start with / so Ruby know this is a regex pattern
* - Have a second / that may be added to end if only 1 exists at start
* - If there are 2 / in pattern then don't add any more
*/
@Test(description = "test regex patterns")
public void exampleRegexParameterValidationOAS3Test() {
final OpenAPI openAPI = new OpenAPIParser()
.readLocation("src/test/resources/3_0/test_regex.yaml", null, new ParseOptions()).getOpenAPI();
final RubyClientCodegen codegen = new RubyClientCodegen();
final String path = "/ping";
final Operation p = openAPI.getPaths().get(path).getGet();
final CodegenOperation op = codegen.fromOperation(path, "get", p, openAPI.getComponents().getSchemas());
// pattern_no_forward_slashes '^pattern$'
Assert.assertEquals(op.allParams.get(0).pattern, "/^pattern$/");
// pattern_two_slashes '/^pattern$/i'
Assert.assertEquals(op.allParams.get(1).pattern, "/^pattern$/i");
// pattern_one_slash_start '/^pattern$'
Assert.assertEquals(op.allParams.get(2).pattern, "/^pattern$/");
// pattern_one_slash_end '^pattern$/'
Assert.assertEquals(op.allParams.get(3).pattern, "/^pattern$/");
// pattern_one_slash_near_end '^pattern$/im'
Assert.assertEquals(op.allParams.get(4).pattern, "/^pattern$/im");
// pattern_dont_escape_backslash '/^pattern\d{3}$/i' NOTE: the double \ is to escape \ in string but is read as single \
Assert.assertEquals(op.allParams.get(5).pattern, "/^pattern\\d{3}$/i");
}
}

View File

@@ -1338,6 +1338,14 @@ components:
format: password
maxLength: 64
minLength: 10
pattern_with_digits:
description: A string that is a 10 digit number. Can have leading zeros.
type: string
pattern: '^\d{10}$'
pattern_with_digits_and_delimiter:
description: A string starting with 'image_' (case insensitive) and one to three digits following i.e. Image_01.
type: string
pattern: '/^image_\d{1,3}$/i'
EnumClass:
type: string
default: '-efg'

View File

@@ -0,0 +1,51 @@
openapi: 3.0.1
info:
title: Test Regex generation for parameter validation
version: 1.0.0
components:
headers:
responses:
OK_200:
description: OK
paths:
/ping:
get:
summary: Get Payment Information
description: Returns the content of a payment object
parameters:
- name: pattern_no_forward_slashes
in: header
schema:
type: string
pattern: '^pattern$'
- name: pattern_two_slashes
in: header
schema:
type: string
pattern: '/^pattern$/i'
- name: pattern_one_slash_start
in: header
schema:
type: string
pattern: '/^pattern$'
- name: pattern_one_slash_end
in: header
schema:
type: string
pattern: '^pattern$/'
- name: pattern_one_slash_near_end
in: header
schema:
type: string
pattern: '^pattern$/im'
- name: pattern_dont_escape_backslash
in: header
schema:
type: string
pattern: '/^pattern\d{3}$/i'
responses:
'200':
$ref: "#/components/responses/OK_200"

View File

@@ -13,7 +13,7 @@ GEM
public_suffix (>= 2.0.2, < 4.0)
autotest (4.4.6)
ZenTest (>= 4.4.1)
autotest-fsevent (0.2.13)
autotest-fsevent (0.2.14)
sys-uname
autotest-growl (0.2.16)
autotest-rails-pure (4.1.2)

View File

@@ -16,5 +16,7 @@ Name | Type | Description | Notes
**date_time** | **DateTime** | | [optional]
**uuid** | **String** | | [optional]
**password** | **String** | |
**pattern_with_digits** | **String** | A string that is a 10 digit number. Can have leading zeros. | [optional]
**pattern_with_digits_and_delimiter** | **String** | A string starting with &#39;image_&#39; (case insensitive) and one to three digits following i.e. Image_01. | [optional]

View File

@@ -40,6 +40,12 @@ module Petstore
attr_accessor :password
# A string that is a 10 digit number. Can have leading zeros.
attr_accessor :pattern_with_digits
# A string starting with 'image_' (case insensitive) and one to three digits following i.e. Image_01.
attr_accessor :pattern_with_digits_and_delimiter
# Attribute mapping from ruby-style variable name to JSON key.
def self.attribute_map
{
@@ -55,7 +61,9 @@ module Petstore
:'date' => :'date',
:'date_time' => :'dateTime',
:'uuid' => :'uuid',
:'password' => :'password'
:'password' => :'password',
:'pattern_with_digits' => :'pattern_with_digits',
:'pattern_with_digits_and_delimiter' => :'pattern_with_digits_and_delimiter'
}
end
@@ -74,7 +82,9 @@ module Petstore
:'date' => :'Date',
:'date_time' => :'DateTime',
:'uuid' => :'String',
:'password' => :'String'
:'password' => :'String',
:'pattern_with_digits' => :'String',
:'pattern_with_digits_and_delimiter' => :'String'
}
end
@@ -137,6 +147,14 @@ module Petstore
if attributes.has_key?(:'password')
self.password = attributes[:'password']
end
if attributes.has_key?(:'pattern_with_digits')
self.pattern_with_digits = attributes[:'pattern_with_digits']
end
if attributes.has_key?(:'pattern_with_digits_and_delimiter')
self.pattern_with_digits_and_delimiter = attributes[:'pattern_with_digits_and_delimiter']
end
end
# Show invalid properties with the reasons. Usually used together with valid?
@@ -211,6 +229,14 @@ module Petstore
invalid_properties.push('invalid value for "password", the character length must be great than or equal to 10.')
end
if !@pattern_with_digits.nil? && @pattern_with_digits !~ Regexp.new(/^\d{10}$/)
invalid_properties.push('invalid value for "pattern_with_digits", must conform to the pattern /^\d{10}$/.')
end
if !@pattern_with_digits_and_delimiter.nil? && @pattern_with_digits_and_delimiter !~ Regexp.new(/^image_\d{1,3}$/i)
invalid_properties.push('invalid value for "pattern_with_digits_and_delimiter", must conform to the pattern /^image_\d{1,3}$/i.')
end
invalid_properties
end
@@ -234,6 +260,8 @@ module Petstore
return false if @password.nil?
return false if @password.to_s.length > 64
return false if @password.to_s.length < 10
return false if !@pattern_with_digits.nil? && @pattern_with_digits !~ Regexp.new(/^\d{10}$/)
return false if !@pattern_with_digits_and_delimiter.nil? && @pattern_with_digits_and_delimiter !~ Regexp.new(/^image_\d{1,3}$/i)
true
end
@@ -339,6 +367,26 @@ module Petstore
@password = password
end
# Custom attribute writer method with validation
# @param [Object] pattern_with_digits Value to be assigned
def pattern_with_digits=(pattern_with_digits)
if !pattern_with_digits.nil? && pattern_with_digits !~ Regexp.new(/^\d{10}$/)
fail ArgumentError, 'invalid value for "pattern_with_digits", must conform to the pattern /^\d{10}$/.'
end
@pattern_with_digits = pattern_with_digits
end
# Custom attribute writer method with validation
# @param [Object] pattern_with_digits_and_delimiter Value to be assigned
def pattern_with_digits_and_delimiter=(pattern_with_digits_and_delimiter)
if !pattern_with_digits_and_delimiter.nil? && pattern_with_digits_and_delimiter !~ Regexp.new(/^image_\d{1,3}$/i)
fail ArgumentError, 'invalid value for "pattern_with_digits_and_delimiter", must conform to the pattern /^image_\d{1,3}$/i.'
end
@pattern_with_digits_and_delimiter = pattern_with_digits_and_delimiter
end
# Checks equality by comparing each attribute.
# @param [Object] Object to be compared
def ==(o)
@@ -356,7 +404,9 @@ module Petstore
date == o.date &&
date_time == o.date_time &&
uuid == o.uuid &&
password == o.password
password == o.password &&
pattern_with_digits == o.pattern_with_digits &&
pattern_with_digits_and_delimiter == o.pattern_with_digits_and_delimiter
end
# @see the `==` method
@@ -368,7 +418,7 @@ module Petstore
# Calculates hash code according to all attributes.
# @return [Fixnum] Hash code
def hash
[integer, int32, int64, number, float, double, string, byte, binary, date, date_time, uuid, password].hash
[integer, int32, int64, number, float, double, string, byte, binary, date, date_time, uuid, password, pattern_with_digits, pattern_with_digits_and_delimiter].hash
end
# Builds the object from hash

View File

@@ -110,4 +110,31 @@ describe 'FormatTest' do
end
end
describe 'test attribute "pattern_with_digits"' do
it 'should accept string "1234567890"' do
@instance.pattern_with_digits = '1234567890'
end
it 'should accept string with leading zero "0123456789"' do
@instance.pattern_with_digits = '0123456789'
end
it 'should reject string with non digits "ABC3456789"' do
expect {@instance.pattern_with_digits = 'ABC3456789'}.to raise_error(ArgumentError)
end
it 'should reject string less than 10 in length "123456789"' do
expect {@instance.pattern_with_digits = '123456789'}.to raise_error(ArgumentError)
end
it 'should reject string more than 10 in length "0123456789123"' do
expect {@instance.pattern_with_digits = '0123456789123'}.to raise_error(ArgumentError)
end
end
describe 'test attribute "pattern_with_digits_and_delimiter"' do
it 'should accept string "Image_01"' do
@instance.pattern_with_digits_and_delimiter = 'Image_01'
end
end
end

View File

@@ -16,6 +16,8 @@ Name | Type | Description | Notes
**date_time** | [**\DateTime**](\DateTime.md) | | [optional]
**uuid** | **string** | | [optional]
**password** | **string** | |
**pattern_with_digits** | **string** | A string that is a 10 digit number. Can have leading zeros. | [optional]
**pattern_with_digits_and_delimiter** | **string** | A string starting with &#39;image_&#39; (case insensitive) and one to three digits following i.e. Image_01. | [optional]
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)

View File

@@ -69,7 +69,9 @@ class FormatTest implements ModelInterface, ArrayAccess
'date' => '\DateTime',
'date_time' => '\DateTime',
'uuid' => 'string',
'password' => 'string'
'password' => 'string',
'pattern_with_digits' => 'string',
'pattern_with_digits_and_delimiter' => 'string'
];
/**
@@ -90,7 +92,9 @@ class FormatTest implements ModelInterface, ArrayAccess
'date' => 'date',
'date_time' => 'date-time',
'uuid' => 'uuid',
'password' => 'password'
'password' => 'password',
'pattern_with_digits' => null,
'pattern_with_digits_and_delimiter' => null
];
/**
@@ -132,7 +136,9 @@ class FormatTest implements ModelInterface, ArrayAccess
'date' => 'date',
'date_time' => 'dateTime',
'uuid' => 'uuid',
'password' => 'password'
'password' => 'password',
'pattern_with_digits' => 'pattern_with_digits',
'pattern_with_digits_and_delimiter' => 'pattern_with_digits_and_delimiter'
];
/**
@@ -153,7 +159,9 @@ class FormatTest implements ModelInterface, ArrayAccess
'date' => 'setDate',
'date_time' => 'setDateTime',
'uuid' => 'setUuid',
'password' => 'setPassword'
'password' => 'setPassword',
'pattern_with_digits' => 'setPatternWithDigits',
'pattern_with_digits_and_delimiter' => 'setPatternWithDigitsAndDelimiter'
];
/**
@@ -174,7 +182,9 @@ class FormatTest implements ModelInterface, ArrayAccess
'date' => 'getDate',
'date_time' => 'getDateTime',
'uuid' => 'getUuid',
'password' => 'getPassword'
'password' => 'getPassword',
'pattern_with_digits' => 'getPatternWithDigits',
'pattern_with_digits_and_delimiter' => 'getPatternWithDigitsAndDelimiter'
];
/**
@@ -250,6 +260,8 @@ class FormatTest implements ModelInterface, ArrayAccess
$this->container['date_time'] = isset($data['date_time']) ? $data['date_time'] : null;
$this->container['uuid'] = isset($data['uuid']) ? $data['uuid'] : null;
$this->container['password'] = isset($data['password']) ? $data['password'] : null;
$this->container['pattern_with_digits'] = isset($data['pattern_with_digits']) ? $data['pattern_with_digits'] : null;
$this->container['pattern_with_digits_and_delimiter'] = isset($data['pattern_with_digits_and_delimiter']) ? $data['pattern_with_digits_and_delimiter'] : null;
}
/**
@@ -325,6 +337,14 @@ class FormatTest implements ModelInterface, ArrayAccess
$invalidProperties[] = "invalid value for 'password', the character length must be bigger than or equal to 10.";
}
if (!is_null($this->container['pattern_with_digits']) && !preg_match("/^\\d{10}$/", $this->container['pattern_with_digits'])) {
$invalidProperties[] = "invalid value for 'pattern_with_digits', must be conform to the pattern /^\\d{10}$/.";
}
if (!is_null($this->container['pattern_with_digits_and_delimiter']) && !preg_match("/^image_\\d{1,3}$/i", $this->container['pattern_with_digits_and_delimiter'])) {
$invalidProperties[] = "invalid value for 'pattern_with_digits_and_delimiter', must be conform to the pattern /^image_\\d{1,3}$/i.";
}
return $invalidProperties;
}
@@ -703,6 +723,64 @@ class FormatTest implements ModelInterface, ArrayAccess
return $this;
}
/**
* Gets pattern_with_digits
*
* @return string|null
*/
public function getPatternWithDigits()
{
return $this->container['pattern_with_digits'];
}
/**
* Sets pattern_with_digits
*
* @param string|null $pattern_with_digits A string that is a 10 digit number. Can have leading zeros.
*
* @return $this
*/
public function setPatternWithDigits($pattern_with_digits)
{
if (!is_null($pattern_with_digits) && (!preg_match("/^\\d{10}$/", $pattern_with_digits))) {
throw new \InvalidArgumentException("invalid value for $pattern_with_digits when calling FormatTest., must conform to the pattern /^\\d{10}$/.");
}
$this->container['pattern_with_digits'] = $pattern_with_digits;
return $this;
}
/**
* Gets pattern_with_digits_and_delimiter
*
* @return string|null
*/
public function getPatternWithDigitsAndDelimiter()
{
return $this->container['pattern_with_digits_and_delimiter'];
}
/**
* Sets pattern_with_digits_and_delimiter
*
* @param string|null $pattern_with_digits_and_delimiter A string starting with 'image_' (case insensitive) and one to three digits following i.e. Image_01.
*
* @return $this
*/
public function setPatternWithDigitsAndDelimiter($pattern_with_digits_and_delimiter)
{
if (!is_null($pattern_with_digits_and_delimiter) && (!preg_match("/^image_\\d{1,3}$/i", $pattern_with_digits_and_delimiter))) {
throw new \InvalidArgumentException("invalid value for $pattern_with_digits_and_delimiter when calling FormatTest., must conform to the pattern /^image_\\d{1,3}$/i.");
}
$this->container['pattern_with_digits_and_delimiter'] = $pattern_with_digits_and_delimiter;
return $this;
}
/**
* Returns true if offset exists. False otherwise.
*

View File

@@ -166,4 +166,18 @@ class FormatTestTest extends \PHPUnit_Framework_TestCase
public function testPropertyPassword()
{
}
/**
* Test attribute "pattern_with_digits"
*/
public function testPropertyPatternWithDigits()
{
}
/**
* Test attribute "pattern_with_digits_and_delimiter"
*/
public function testPropertyPatternWithDigitsAndDelimiter()
{
}
}

View File

@@ -69,6 +69,12 @@ public class FormatTest {
@JsonProperty("password")
private String password;
@JsonProperty("pattern_with_digits")
private String patternWithDigits;
@JsonProperty("pattern_with_digits_and_delimiter")
private String patternWithDigitsAndDelimiter;
public FormatTest integer(Integer integer) {
this.integer = integer;
return this;
@@ -343,6 +349,46 @@ public class FormatTest {
this.password = password;
}
public FormatTest patternWithDigits(String patternWithDigits) {
this.patternWithDigits = patternWithDigits;
return this;
}
/**
* A string that is a 10 digit number. Can have leading zeros.
* @return patternWithDigits
**/
@JsonProperty("pattern_with_digits")
@ApiModelProperty(value = "A string that is a 10 digit number. Can have leading zeros.")
@Pattern(regexp="^\\d{10}$")
public String getPatternWithDigits() {
return patternWithDigits;
}
public void setPatternWithDigits(String patternWithDigits) {
this.patternWithDigits = patternWithDigits;
}
public FormatTest patternWithDigitsAndDelimiter(String patternWithDigitsAndDelimiter) {
this.patternWithDigitsAndDelimiter = patternWithDigitsAndDelimiter;
return this;
}
/**
* A string starting with &#39;image_&#39; (case insensitive) and one to three digits following i.e. Image_01.
* @return patternWithDigitsAndDelimiter
**/
@JsonProperty("pattern_with_digits_and_delimiter")
@ApiModelProperty(value = "A string starting with 'image_' (case insensitive) and one to three digits following i.e. Image_01.")
@Pattern(regexp="/^image_\\d{1,3}$/i")
public String getPatternWithDigitsAndDelimiter() {
return patternWithDigitsAndDelimiter;
}
public void setPatternWithDigitsAndDelimiter(String patternWithDigitsAndDelimiter) {
this.patternWithDigitsAndDelimiter = patternWithDigitsAndDelimiter;
}
@Override
public boolean equals(java.lang.Object o) {
@@ -365,12 +411,14 @@ public class FormatTest {
Objects.equals(this.date, formatTest.date) &&
Objects.equals(this.dateTime, formatTest.dateTime) &&
Objects.equals(this.uuid, formatTest.uuid) &&
Objects.equals(this.password, formatTest.password);
Objects.equals(this.password, formatTest.password) &&
Objects.equals(this.patternWithDigits, formatTest.patternWithDigits) &&
Objects.equals(this.patternWithDigitsAndDelimiter, formatTest.patternWithDigitsAndDelimiter);
}
@Override
public int hashCode() {
return Objects.hash(integer, int32, int64, number, _float, _double, string, _byte, binary, date, dateTime, uuid, password);
return Objects.hash(integer, int32, int64, number, _float, _double, string, _byte, binary, date, dateTime, uuid, password, patternWithDigits, patternWithDigitsAndDelimiter);
}
@@ -392,6 +440,8 @@ public class FormatTest {
sb.append(" dateTime: ").append(toIndentedString(dateTime)).append("\n");
sb.append(" uuid: ").append(toIndentedString(uuid)).append("\n");
sb.append(" password: ").append(toIndentedString(password)).append("\n");
sb.append(" patternWithDigits: ").append(toIndentedString(patternWithDigits)).append("\n");
sb.append(" patternWithDigitsAndDelimiter: ").append(toIndentedString(patternWithDigitsAndDelimiter)).append("\n");
sb.append("}");
return sb.toString();
}