Skip to content
This repository was archived by the owner on Feb 9, 2021. It is now read-only.

Commit bf57a99

Browse files
michelealbanowing328
authored andcommitted
Rebased to current upstream/master. (OpenAPITools#4514)
Tests for python client, comprising support for additional_properties and arrays. There are ugly workarounds for when there are discriminators, since the python client generator does not fully handle them. Cool indentation of test files.
1 parent fc4563b commit bf57a99

File tree

12 files changed

+443
-54
lines changed

12 files changed

+443
-54
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientCodegen.java

+178
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,184 @@ public String toRegularExpression(String pattern) {
695695
return addRegularExpressionDelimiter(pattern);
696696
}
697697

698+
@Override
699+
public String toExampleValue(Schema schema) {
700+
return toExampleValueRecursive(schema, new ArrayList<String>(), 5);
701+
}
702+
703+
private String toExampleValueRecursive(Schema schema, List<String> included_schemas, int indentation) {
704+
String indentation_string = "";
705+
for (int i=0 ; i< indentation ; i++) indentation_string += " ";
706+
String example = super.toExampleValue(schema);
707+
708+
// correct "true"s into "True"s, since super.toExampleValue uses "toString()" on Java booleans
709+
if (ModelUtils.isBooleanSchema(schema) && null!=example) {
710+
if ("false".equalsIgnoreCase(example)) example = "False";
711+
else example = "True";
712+
}
713+
714+
// correct "&#39;"s into "'"s after toString()
715+
if (ModelUtils.isStringSchema(schema) && schema.getDefault() != null) {
716+
example = (String) schema.getDefault();
717+
}
718+
719+
if (StringUtils.isNotBlank(example) && !"null".equals(example)) {
720+
if (ModelUtils.isStringSchema(schema)) {
721+
example = "'" + example + "'";
722+
}
723+
return example;
724+
}
725+
726+
if (schema.getEnum() != null && !schema.getEnum().isEmpty()) {
727+
// Enum case:
728+
example = schema.getEnum().get(0).toString();
729+
if (ModelUtils.isStringSchema(schema)) {
730+
example = "'" + escapeText(example) + "'";
731+
}
732+
if (null == example)
733+
LOGGER.warn("Empty enum. Cannot built an example!");
734+
735+
return example;
736+
} else if (null != schema.get$ref()) {
737+
// $ref case:
738+
Map<String, Schema> allDefinitions = ModelUtils.getSchemas(this.openAPI);
739+
String ref = ModelUtils.getSimpleRef(schema.get$ref());
740+
if (allDefinitions != null) {
741+
Schema refSchema = allDefinitions.get(ref);
742+
if (null == refSchema) {
743+
return "None";
744+
} else {
745+
String refTitle = refSchema.getTitle();
746+
if (StringUtils.isBlank(refTitle) || "null".equals(refTitle)) {
747+
refSchema.setTitle(ref);
748+
}
749+
if (StringUtils.isNotBlank(schema.getTitle()) && !"null".equals(schema.getTitle())) {
750+
included_schemas.add(schema.getTitle());
751+
}
752+
return toExampleValueRecursive(refSchema, included_schemas, indentation);
753+
}
754+
} else {
755+
LOGGER.warn("allDefinitions not defined in toExampleValue!\n");
756+
}
757+
}
758+
if (ModelUtils.isDateSchema(schema)) {
759+
example = "datetime.datetime.strptime('1975-12-30', '%Y-%m-%d').date()";
760+
return example;
761+
} else if (ModelUtils.isDateTimeSchema(schema)) {
762+
example = "datetime.datetime.strptime('2013-10-20 19:20:30.00', '%Y-%m-%d %H:%M:%S.%f')";
763+
return example;
764+
} else if (ModelUtils.isBinarySchema(schema)) {
765+
example = "bytes(b'blah')";
766+
return example;
767+
} else if (ModelUtils.isByteArraySchema(schema)) {
768+
example = "YQ==";
769+
} else if (ModelUtils.isStringSchema(schema)) {
770+
// a BigDecimal:
771+
if ("Number".equalsIgnoreCase(schema.getFormat())) {return "1";}
772+
if (StringUtils.isNotBlank(schema.getPattern())) return "'a'"; // I cheat here, since it would be too complicated to generate a string from a regexp
773+
int len = 0;
774+
if (null != schema.getMinLength()) len = schema.getMinLength().intValue();
775+
if (len < 1) len = 1;
776+
example = "";
777+
for (int i=0;i<len;i++) example += i;
778+
} else if (ModelUtils.isIntegerSchema(schema)) {
779+
if (schema.getMinimum() != null)
780+
example = schema.getMinimum().toString();
781+
else
782+
example = "56";
783+
} else if (ModelUtils.isNumberSchema(schema)) {
784+
if (schema.getMinimum() != null)
785+
example = schema.getMinimum().toString();
786+
else
787+
example = "1.337";
788+
} else if (ModelUtils.isBooleanSchema(schema)) {
789+
example = "True";
790+
} else if (ModelUtils.isArraySchema(schema)) {
791+
if (StringUtils.isNotBlank(schema.getTitle()) && !"null".equals(schema.getTitle())) {
792+
included_schemas.add(schema.getTitle());
793+
}
794+
ArraySchema arrayschema = (ArraySchema) schema;
795+
example = "[\n" + indentation_string + toExampleValueRecursive(arrayschema.getItems(), included_schemas, indentation+1) + "\n" + indentation_string + "]";
796+
} else if (ModelUtils.isMapSchema(schema)) {
797+
if (StringUtils.isNotBlank(schema.getTitle()) && !"null".equals(schema.getTitle())) {
798+
included_schemas.add(schema.getTitle());
799+
}
800+
Object additionalObject = schema.getAdditionalProperties();
801+
if (additionalObject instanceof Schema) {
802+
Schema additional = (Schema) additionalObject;
803+
String the_key = "'key'";
804+
if (additional.getEnum() != null && !additional.getEnum().isEmpty()) {
805+
the_key = additional.getEnum().get(0).toString();
806+
if (ModelUtils.isStringSchema(additional)) {
807+
the_key = "'" + escapeText(the_key) + "'";
808+
}
809+
}
810+
example = "{\n" + indentation_string + the_key + " : " + toExampleValueRecursive(additional, included_schemas, indentation+1) + "\n" + indentation_string + "}";
811+
} else {
812+
example = "{ }";
813+
}
814+
} else if (ModelUtils.isObjectSchema(schema)) {
815+
if (StringUtils.isBlank(schema.getTitle())) {
816+
example = "None";
817+
return example;
818+
}
819+
820+
// I remove any property that is a discriminator, since it is not well supported by the python generator
821+
String toExclude = null;
822+
if (schema.getDiscriminator()!=null) {
823+
toExclude = schema.getDiscriminator().getPropertyName();
824+
}
825+
826+
example = packageName + ".models." + underscore(schema.getTitle())+"."+schema.getTitle()+"(";
827+
828+
// if required only:
829+
// List<String> reqs = schema.getRequired();
830+
831+
// if required and optionals
832+
List<String> reqs = new ArrayList<String>();
833+
for (Object toAdd : schema.getProperties().keySet())
834+
reqs.add((String)toAdd);
835+
836+
Map<String, Schema> properties = schema.getProperties();
837+
Set<String> propkeys = null;
838+
if (properties != null) propkeys = properties.keySet();
839+
if (toExclude != null && reqs.contains(toExclude)) {
840+
reqs.remove(toExclude);
841+
}
842+
for (String toRemove : included_schemas) {
843+
if (reqs.contains(toRemove)) {
844+
reqs.remove(toRemove);
845+
}
846+
}
847+
if (StringUtils.isNotBlank(schema.getTitle()) && !"null".equals(schema.getTitle())) {
848+
included_schemas.add(schema.getTitle());
849+
}
850+
if (null != schema.getRequired()) for (Object toAdd : schema.getRequired()) {
851+
reqs.add((String)toAdd);
852+
}
853+
if (null!=propkeys) for (String propname : propkeys) {
854+
Schema schema2 = properties.get(propname);
855+
if (reqs.contains(propname)) {
856+
String refTitle = schema2.getTitle();
857+
if (StringUtils.isBlank(refTitle) || "null".equals(refTitle)) {
858+
schema2.setTitle(propname);
859+
}
860+
example += "\n" + indentation_string + underscore(propname) + " = "+
861+
toExampleValueRecursive(schema2, included_schemas, indentation+1)+", ";
862+
}
863+
}
864+
example +=")";
865+
} else {
866+
LOGGER.warn("Type " + schema.getType() + " not handled properly in toExampleValue");
867+
}
868+
869+
if (ModelUtils.isStringSchema(schema)) {
870+
example = "'" + escapeText(example) + "'";
871+
}
872+
873+
return example;
874+
}
875+
698876
@Override
699877
public void setParameterExampleValue(CodegenParameter p) {
700878
String example;

modules/openapi-generator/src/main/resources/python/model_test.mustache

+24-4
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@
55
from __future__ import absolute_import
66

77
import unittest
8+
import datetime
89

910
{{#models}}
1011
{{#model}}
1112
import {{packageName}}
1213
from {{modelPackage}}.{{classFilename}} import {{classname}} # noqa: E501
1314
from {{packageName}}.rest import ApiException
1415

15-
1616
class Test{{classname}}(unittest.TestCase):
1717
"""{{classname}} unit test stubs"""
1818

@@ -22,11 +22,31 @@ class Test{{classname}}(unittest.TestCase):
2222
def tearDown(self):
2323
pass
2424

25+
def make_instance(self, include_optional):
26+
"""Test {{classname}}
27+
include_option is a boolean, when False only required
28+
params are included, when True both required and
29+
optional params are included """
30+
# model = {{packageName}}.models.{{classFilename}}.{{classname}}() # noqa: E501
31+
if include_optional :
32+
return {{classname}}(
33+
{{#vars}}
34+
{{name}} = {{#example}}{{{.}}}{{/example}}{{^example}}None{{/example}}{{#hasMore}}, {{/hasMore}}
35+
{{/vars}}
36+
)
37+
else :
38+
return {{classname}}(
39+
{{#vars}}
40+
{{#required}}
41+
{{name}} = {{#example}}{{{.}}}{{/example}}{{^example}}None{{/example}},
42+
{{/required}}
43+
{{/vars}}
44+
)
45+
2546
def test{{classname}}(self):
2647
"""Test {{classname}}"""
27-
# FIXME: construct object with mandatory attributes with example values
28-
# model = {{packageName}}.models.{{classFilename}}.{{classname}}() # noqa: E501
29-
pass
48+
inst_req_only = self.make_instance(include_optional=False)
49+
inst_req_and_optional = self.make_instance(include_optional=True)
3050

3151
{{/model}}
3252
{{/models}}

samples/client/petstore/python/test/test_animal.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55
66
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ # noqa: E501
77
8-
OpenAPI spec version: 1.0.0
8+
The version of the OpenAPI document: 1.0.0
99
Generated by: https://openapi-generator.tech
1010
"""
1111

1212

1313
from __future__ import absolute_import
1414

1515
import unittest
16+
import datetime
1617

1718
import petstore_api
1819
from petstore_api.models.animal import Animal # noqa: E501
1920
from petstore_api.rest import ApiException
2021

21-
2222
class TestAnimal(unittest.TestCase):
2323
"""Animal unit test stubs"""
2424

@@ -28,11 +28,26 @@ def setUp(self):
2828
def tearDown(self):
2929
pass
3030

31+
def make_instance(self, include_optional):
32+
"""Test Animal
33+
include_option is a boolean, when False only required
34+
params are included, when True both required and
35+
optional params are included """
36+
# model = petstore_api.models.animal.Animal() # noqa: E501
37+
if include_optional :
38+
return Animal(
39+
class_name = '0',
40+
color = 'red'
41+
)
42+
else :
43+
return Animal(
44+
class_name = '0',
45+
)
46+
3147
def testAnimal(self):
3248
"""Test Animal"""
33-
# FIXME: construct object with mandatory attributes with example values
34-
# model = petstore_api.models.animal.Animal() # noqa: E501
35-
pass
49+
inst_req_only = self.make_instance(include_optional=False)
50+
inst_req_and_optional = self.make_instance(include_optional=True)
3651

3752

3853
if __name__ == '__main__':

samples/client/petstore/python/test/test_cat.py

+18-5
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55
66
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ # noqa: E501
77
8-
OpenAPI spec version: 1.0.0
8+
The version of the OpenAPI document: 1.0.0
99
Generated by: https://openapi-generator.tech
1010
"""
1111

1212

1313
from __future__ import absolute_import
1414

1515
import unittest
16+
import datetime
1617

1718
import petstore_api
1819
from petstore_api.models.cat import Cat # noqa: E501
1920
from petstore_api.rest import ApiException
2021

21-
2222
class TestCat(unittest.TestCase):
2323
"""Cat unit test stubs"""
2424

@@ -28,11 +28,24 @@ def setUp(self):
2828
def tearDown(self):
2929
pass
3030

31+
def make_instance(self, include_optional):
32+
"""Test Cat
33+
include_option is a boolean, when False only required
34+
params are included, when True both required and
35+
optional params are included """
36+
# model = petstore_api.models.cat.Cat() # noqa: E501
37+
if include_optional :
38+
return Cat(
39+
declawed = True
40+
)
41+
else :
42+
return Cat(
43+
)
44+
3145
def testCat(self):
3246
"""Test Cat"""
33-
# FIXME: construct object with mandatory attributes with example values
34-
# model = petstore_api.models.cat.Cat() # noqa: E501
35-
pass
47+
inst_req_only = self.make_instance(include_optional=False)
48+
inst_req_and_optional = self.make_instance(include_optional=True)
3649

3750

3851
if __name__ == '__main__':

samples/client/petstore/python/test/test_category.py

+20-5
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,20 @@
55
66
This spec is mainly for testing Petstore server and contains fake endpoints, models. Please do not use this for any other purpose. Special characters: \" \\ # noqa: E501
77
8-
OpenAPI spec version: 1.0.0
8+
The version of the OpenAPI document: 1.0.0
99
Generated by: https://openapi-generator.tech
1010
"""
1111

1212

1313
from __future__ import absolute_import
1414

1515
import unittest
16+
import datetime
1617

1718
import petstore_api
1819
from petstore_api.models.category import Category # noqa: E501
1920
from petstore_api.rest import ApiException
2021

21-
2222
class TestCategory(unittest.TestCase):
2323
"""Category unit test stubs"""
2424

@@ -28,11 +28,26 @@ def setUp(self):
2828
def tearDown(self):
2929
pass
3030

31+
def make_instance(self, include_optional):
32+
"""Test Category
33+
include_option is a boolean, when False only required
34+
params are included, when True both required and
35+
optional params are included """
36+
# model = petstore_api.models.category.Category() # noqa: E501
37+
if include_optional :
38+
return Category(
39+
id = 56,
40+
name = 'default-name'
41+
)
42+
else :
43+
return Category(
44+
name = 'default-name',
45+
)
46+
3147
def testCategory(self):
3248
"""Test Category"""
33-
# FIXME: construct object with mandatory attributes with example values
34-
# model = petstore_api.models.category.Category() # noqa: E501
35-
pass
49+
inst_req_only = self.make_instance(include_optional=False)
50+
inst_req_and_optional = self.make_instance(include_optional=True)
3651

3752

3853
if __name__ == '__main__':

0 commit comments

Comments
 (0)