Skip to content

Commit

Permalink
adding support for signed integers in x-field-pattern (#456)
Browse files Browse the repository at this point in the history
* adding support for signed integers in x-field-pattern

* remove signed property from checksum checksum

* correcting min and max val for signed integers
  • Loading branch information
Vibaswan authored Jan 8, 2024
1 parent 5780616 commit c9543a5
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 3 deletions.
9 changes: 8 additions & 1 deletion MODELGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,13 @@ x-field-pattern:
Pre-processing will write minimum and maximum values based on the length.
Length will be ignored for mac, ipv4, ipv6 formats.
type: integer
signed:
description: >-
Valid only if the format is of type integer.
Indicates whether the integer value is signed or unsigned.
If the property is not specified the value is considered as unsigned.
Its a boolean value which is optional in nature.
type: boolean
default:
description: >-
The default value of the pattern value.
Expand Down Expand Up @@ -344,4 +351,4 @@ ipv4:
address:
choice: value
value: 0.0.0.0
```
```
31 changes: 29 additions & 2 deletions openapiart/bundler.py
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,19 @@ def _validate_x_field_pattern(self, xpattern_path):
str(xpattern_path.full_path)
)
)
if "signed" in xpattern:
if xpattern["format"] != "integer":
self._errors.append(
"signed property can only be used if the format is set to integer in property {}".format(
str(xpattern_path.full_path)
)
)
if not isinstance(xpattern["signed"], bool):
self._errors.append(
"invalid value {} in {}, signed property can either be true or false".format(
str(xpattern["signed"]), str(xpattern_path.full_path)
)
)
valid_formats = ["integer", "ipv4", "ipv6", "mac", "checksum"]
if xpattern["format"] not in valid_formats:
self._errors.append(
Expand Down Expand Up @@ -1038,6 +1051,8 @@ def _apply_common_x_field_pattern_properties(
finalised_format = "uint32"
if "length" in xpattern and xpattern["length"] > 32:
finalised_format = "uint64"
if xpattern.get("signed", False):
finalised_format = finalised_format[1:]
elif fmt is not None:
finalised_format = fmt

Expand All @@ -1047,10 +1062,22 @@ def _apply_common_x_field_pattern_properties(
else:
schema["format"] = finalised_format
if "length" in xpattern and int(xpattern["length"]) not in [32, 64]:
min_val = (
-(2 ** (int(xpattern["length"]) - 1))
if xpattern.get("signed", False)
else None
)
max_val = 2 ** int(xpattern["length"]) - 1
if xpattern.get("signed", False):
max_val = 2 ** (int(xpattern["length"]) - 1) - 1
if property_name == "values":
schema["items"]["maximum"] = 2 ** int(xpattern["length"]) - 1
if min_val is not None:
schema["items"]["minimum"] = min_val
schema["items"]["maximum"] = max_val
else:
schema["maximum"] = 2 ** int(xpattern["length"]) - 1
if min_val is not None:
schema["minimum"] = min_val
schema["maximum"] = max_val

def _resolve_recursive_x_include(self, include_value):
if "x-include" in include_value:
Expand Down
3 changes: 3 additions & 0 deletions openapiart/tests/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,9 @@ components:
minimum: 64
maximum: 9000
x-field-uid: 52
signed_integer_pattern:
$ref: "../pattern/pattern.yaml#/components/schemas/SignedIntegerPattern"
x-field-uid: 53

WObject:
required: [w_name]
Expand Down
15 changes: 15 additions & 0 deletions openapiart/tests/pattern/invalid-pattern.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,18 @@ components:
default: 0
features: [count]
x-field-uid: 7
signed_value_without_int:
x-field-pattern:
format: mac
default: "00:00:00:00:00:00"
features: [count, auto]
signed: true
x-field-uid: 8
wrong_int_signed_value:
x-field-pattern:
format: integer
length: 2
signed: 45
default: 0
features: [count]
x-field-uid: 9
12 changes: 12 additions & 0 deletions openapiart/tests/pattern/pattern.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -49,3 +49,15 @@ components:
x-field-pattern:
format: checksum
x-field-uid: 1
SignedIntegerPattern:
description: Test signed integer pattern
type: object
properties:
integer:
x-field-pattern:
format: integer
default: 0
signed: true
length: 8
features: [count]
x-field-uid: 1
24 changes: 24 additions & 0 deletions openapiart/tests/test_integer_format.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,30 @@ def test_format_integer_pattern(default_config):
assert dec._TYPES.get("count").get("format") == "uint32"


def test_format_signed_integer_pattern(default_config):
pat = default_config.signed_integer_pattern.integer
val = pat._TYPES.get("value")
assert val.get("format") == "int32"
assert val.get("minimum") == -128
assert val.get("maximum") == 127
inc = pat.increment
assert inc._TYPES.get("start").get("format") == "int32"
assert inc._TYPES.get("step").get("format") == "int32"
assert inc._TYPES.get("count").get("format") == "int32"
dec = pat.decrement
assert dec._TYPES.get("start").get("format") == "int32"
assert dec._TYPES.get("step").get("format") == "int32"
assert dec._TYPES.get("count").get("format") == "int32"
pat.value = -456
error_msg = (
"got -456 of type <class 'int'> , expected min -128, expected max 127"
)
with pytest.raises(Exception) as execinfo:
default_config.serialize("dict")
error_value = execinfo.value.args[0]
assert error_msg in error_value


def test_format_count_pattern(default_config):
ipv4 = default_config.ipv4_pattern.ipv4
assert ipv4.increment._TYPES.get("count").get("format") == "uint32"
Expand Down
2 changes: 2 additions & 0 deletions openapiart/tests/test_validate_x_field_pattern.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ def test_validate_pattern():
"components.schemas.Config.properties.integer.x-field-pattern property using x-field-pattern with format integer must contain length property",
"components.schemas.Config.properties.wrong.x-field-pattern has unspported format random , valid formats are ['integer', 'ipv4', 'ipv6', 'mac', 'checksum']",
"components.schemas.Config.properties.int_128.x-field-pattern property using x-field-pattern with format integer cannot have length greater than 64",
"signed property can only be used if the format is set to integer in property components.schemas.Config.properties.signed_value_without_int.x-field-pattern",
"invalid value 45 in components.schemas.Config.properties.wrong_int_signed_value.x-field-pattern, signed property can either be true or false",
]
with pytest.raises(Exception) as execinfo:
create_openapi_artifacts(
Expand Down

0 comments on commit c9543a5

Please sign in to comment.