-
Notifications
You must be signed in to change notification settings - Fork 38
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #123 from mirumee/fix_decode_and_parse_application
Change BaseModel to apply parse and serialize methods on every list element
- Loading branch information
Showing
11 changed files
with
503 additions
and
81 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
241 changes: 241 additions & 0 deletions
241
tests/client_generators/dependencies/test_base_model.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,241 @@ | ||
from typing import List, Optional | ||
|
||
import pytest | ||
|
||
from ariadne_codegen.client_generators.dependencies.base_model import BaseModel | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"annotation, value, expected_args", | ||
[ | ||
(str, "a", {"a"}), | ||
(Optional[str], "a", {"a"}), | ||
(Optional[str], None, set()), | ||
(List[str], ["a", "b"], {"a", "b"}), | ||
(List[Optional[str]], ["a", None], {"a"}), | ||
(Optional[List[str]], ["a", "b"], {"a", "b"}), | ||
(Optional[List[str]], None, set()), | ||
(Optional[List[Optional[str]]], ["a", None], {"a"}), | ||
(Optional[List[Optional[str]]], None, set()), | ||
(List[List[str]], [["a", "b"], ["c", "d"]], {"a", "b", "c", "d"}), | ||
(Optional[List[List[str]]], [["a", "b"], ["c", "d"]], {"a", "b", "c", "d"}), | ||
(Optional[List[List[str]]], None, set()), | ||
( | ||
Optional[List[Optional[List[str]]]], | ||
[["a", "b"], ["c", "d"]], | ||
{"a", "b", "c", "d"}, | ||
), | ||
(Optional[List[Optional[List[str]]]], None, set()), | ||
(Optional[List[Optional[List[str]]]], [["a", "b"], None], {"a", "b"}), | ||
( | ||
Optional[List[Optional[List[Optional[str]]]]], | ||
[["a", "b"], ["c", "d"]], | ||
{"a", "b", "c", "d"}, | ||
), | ||
(Optional[List[Optional[List[Optional[str]]]]], None, set()), | ||
(Optional[List[Optional[List[Optional[str]]]]], [["a", "b"], None], {"a", "b"}), | ||
( | ||
Optional[List[Optional[List[Optional[str]]]]], | ||
[["a", None], ["b", None]], | ||
{"a", "b"}, | ||
), | ||
], | ||
) | ||
def test_parse_obj_applies_parse_on_every_list_element( | ||
annotation, value, expected_args, mocker | ||
): | ||
mocked_parse = mocker.MagicMock(side_effect=lambda s: s) | ||
mocker.patch( | ||
"ariadne_codegen.client_generators.dependencies.base_model." | ||
"SCALARS_PARSE_FUNCTIONS", | ||
{str: mocked_parse}, | ||
) | ||
|
||
class TestModel(BaseModel): | ||
field: annotation | ||
|
||
TestModel.parse_obj({"field": value}) | ||
|
||
assert mocked_parse.call_count == len(expected_args) | ||
assert {c.args[0] for c in mocked_parse.call_args_list} == expected_args | ||
|
||
|
||
def test_parse_obj_doesnt_apply_parse_on_not_matching_type(mocker): | ||
mocked_parse = mocker.MagicMock(side_effect=lambda s: s) | ||
mocker.patch( | ||
"ariadne_codegen.client_generators.dependencies.base_model." | ||
"SCALARS_PARSE_FUNCTIONS", | ||
{str: mocked_parse}, | ||
) | ||
|
||
class TestModel(BaseModel): | ||
field_a: int | ||
field_b: Optional[int] | ||
field_c: Optional[int] | ||
field_d: List[int] | ||
field_e: Optional[List[int]] | ||
field_f: Optional[List[int]] | ||
field_g: Optional[List[Optional[int]]] | ||
field_h: Optional[List[Optional[int]]] | ||
field_i: Optional[List[Optional[int]]] | ||
|
||
TestModel.parse_obj( | ||
{ | ||
"field_a": 1, | ||
"field_b": 2, | ||
"field_c": None, | ||
"field_d": [3, 4], | ||
"field_e": [5, 6], | ||
"field_f": None, | ||
"field_g": [7, 8], | ||
"field_h": [9, None], | ||
"field_i": None, | ||
} | ||
) | ||
|
||
assert not mocked_parse.called | ||
|
||
|
||
def test_parse_obj_applies_parse_only_once_for_every_element(mocker): | ||
mocked_parse = mocker.MagicMock(side_effect=lambda s: s) | ||
mocker.patch( | ||
"ariadne_codegen.client_generators.dependencies.base_model." | ||
"SCALARS_PARSE_FUNCTIONS", | ||
{str: mocked_parse}, | ||
) | ||
|
||
class TestModelC(BaseModel): | ||
value: str | ||
|
||
class TestModelB(BaseModel): | ||
value: str | ||
field_c: TestModelC | ||
|
||
class TestModelA(BaseModel): | ||
value: str | ||
field_b: TestModelB | ||
|
||
TestModelA.parse_obj( | ||
{"value": "a", "field_b": {"value": "b", "field_c": {"value": "c"}}} | ||
) | ||
|
||
assert mocked_parse.call_count == 3 | ||
assert {c.args[0] for c in mocked_parse.call_args_list} == {"a", "b", "c"} | ||
|
||
|
||
@pytest.mark.parametrize( | ||
"annotation, value, expected_args", | ||
[ | ||
(str, "a", {"a"}), | ||
(Optional[str], "a", {"a"}), | ||
(Optional[str], None, set()), | ||
(List[str], ["a", "b"], {"a", "b"}), | ||
(List[Optional[str]], ["a", None], {"a"}), | ||
(Optional[List[str]], ["a", "b"], {"a", "b"}), | ||
(Optional[List[str]], None, set()), | ||
(Optional[List[Optional[str]]], ["a", None], {"a"}), | ||
(Optional[List[Optional[str]]], None, set()), | ||
(List[List[str]], [["a", "b"], ["c", "d"]], {"a", "b", "c", "d"}), | ||
(Optional[List[List[str]]], [["a", "b"], ["c", "d"]], {"a", "b", "c", "d"}), | ||
(Optional[List[List[str]]], None, set()), | ||
( | ||
Optional[List[Optional[List[str]]]], | ||
[["a", "b"], ["c", "d"]], | ||
{"a", "b", "c", "d"}, | ||
), | ||
(Optional[List[Optional[List[str]]]], None, set()), | ||
(Optional[List[Optional[List[str]]]], [["a", "b"], None], {"a", "b"}), | ||
( | ||
Optional[List[Optional[List[Optional[str]]]]], | ||
[["a", "b"], ["c", "d"]], | ||
{"a", "b", "c", "d"}, | ||
), | ||
(Optional[List[Optional[List[Optional[str]]]]], None, set()), | ||
(Optional[List[Optional[List[Optional[str]]]]], [["a", "b"], None], {"a", "b"}), | ||
( | ||
Optional[List[Optional[List[Optional[str]]]]], | ||
[["a", None], ["b", None]], | ||
{"a", "b"}, | ||
), | ||
], | ||
) | ||
def test_dict_applies_serialize_on_every_list_element( | ||
annotation, value, expected_args, mocker | ||
): | ||
mocked_serialize = mocker.MagicMock(side_effect=lambda s: s) | ||
mocker.patch( | ||
"ariadne_codegen.client_generators.dependencies.base_model." | ||
"SCALARS_SERIALIZE_FUNCTIONS", | ||
{str: mocked_serialize}, | ||
) | ||
|
||
class TestModel(BaseModel): | ||
field: annotation | ||
|
||
TestModel.parse_obj({"field": value}).dict() | ||
|
||
assert mocked_serialize.call_count == len(expected_args) | ||
assert {c.args[0] for c in mocked_serialize.call_args_list} == expected_args | ||
|
||
|
||
def test_dict_doesnt_apply_serialize_on_not_matching_type(mocker): | ||
mocked_serialize = mocker.MagicMock(side_effect=lambda s: s) | ||
mocker.patch( | ||
"ariadne_codegen.client_generators.dependencies.base_model." | ||
"SCALARS_SERIALIZE_FUNCTIONS", | ||
{str: mocked_serialize}, | ||
) | ||
|
||
class TestModel(BaseModel): | ||
field_a: int | ||
field_b: Optional[int] | ||
field_c: Optional[int] | ||
field_d: List[int] | ||
field_e: Optional[List[int]] | ||
field_f: Optional[List[int]] | ||
field_g: Optional[List[Optional[int]]] | ||
field_h: Optional[List[Optional[int]]] | ||
field_i: Optional[List[Optional[int]]] | ||
|
||
TestModel.parse_obj( | ||
{ | ||
"field_a": 1, | ||
"field_b": 2, | ||
"field_c": None, | ||
"field_d": [3, 4], | ||
"field_e": [5, 6], | ||
"field_f": None, | ||
"field_g": [7, 8], | ||
"field_h": [9, None], | ||
"field_i": None, | ||
} | ||
).dict() | ||
|
||
assert not mocked_serialize.called | ||
|
||
|
||
def test_dict_applies_serialize_only_once_for_every_element(mocker): | ||
mocked_serialize = mocker.MagicMock(side_effect=lambda s: s) | ||
mocker.patch( | ||
"ariadne_codegen.client_generators.dependencies.base_model." | ||
"SCALARS_SERIALIZE_FUNCTIONS", | ||
{str: mocked_serialize}, | ||
) | ||
|
||
class TestModelC(BaseModel): | ||
value: str | ||
|
||
class TestModelB(BaseModel): | ||
value: str | ||
field_c: TestModelC | ||
|
||
class TestModelA(BaseModel): | ||
value: str | ||
field_b: TestModelB | ||
|
||
TestModelA.parse_obj( | ||
{"value": "a", "field_b": {"value": "b", "field_c": {"value": "c"}}} | ||
).dict() | ||
|
||
assert mocked_serialize.call_count == 3 | ||
assert {c.args[0] for c in mocked_serialize.call_args_list} == {"a", "b", "c"} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.