|  | 
|  | 1 | +import json | 
|  | 2 | +from io import BytesIO | 
|  | 3 | + | 
|  | 4 | +import pytest | 
|  | 5 | +from rest_framework.exceptions import ParseError | 
|  | 6 | + | 
|  | 7 | +from rest_framework_json_api.parsers import JSONParser | 
|  | 8 | +from rest_framework_json_api.utils import format_value | 
|  | 9 | +from tests.views import BasicModelViewSet | 
|  | 10 | + | 
|  | 11 | + | 
|  | 12 | +class TestJSONParser: | 
|  | 13 | +    @pytest.fixture | 
|  | 14 | +    def parser(self): | 
|  | 15 | +        return JSONParser() | 
|  | 16 | + | 
|  | 17 | +    @pytest.fixture | 
|  | 18 | +    def parse(self, parser, parser_context): | 
|  | 19 | +        def parse_wrapper(data): | 
|  | 20 | +            stream = BytesIO(json.dumps(data).encode("utf-8")) | 
|  | 21 | +            return parser.parse(stream, None, parser_context) | 
|  | 22 | + | 
|  | 23 | +        return parse_wrapper | 
|  | 24 | + | 
|  | 25 | +    @pytest.fixture | 
|  | 26 | +    def parser_context(self, rf): | 
|  | 27 | +        return {"request": rf.post("/"), "kwargs": {}, "view": BasicModelViewSet()} | 
|  | 28 | + | 
|  | 29 | +    @pytest.mark.parametrize( | 
|  | 30 | +        "format_field_names", | 
|  | 31 | +        [ | 
|  | 32 | +            None, | 
|  | 33 | +            "dasherize", | 
|  | 34 | +            "camelize", | 
|  | 35 | +            "capitalize", | 
|  | 36 | +            "underscore", | 
|  | 37 | +        ], | 
|  | 38 | +    ) | 
|  | 39 | +    def test_parse_formats_field_names( | 
|  | 40 | +        self, | 
|  | 41 | +        settings, | 
|  | 42 | +        format_field_names, | 
|  | 43 | +        parse, | 
|  | 44 | +    ): | 
|  | 45 | +        settings.JSON_API_FORMAT_FIELD_NAMES = format_field_names | 
|  | 46 | + | 
|  | 47 | +        data = { | 
|  | 48 | +            "data": { | 
|  | 49 | +                "id": "123", | 
|  | 50 | +                "type": "BasicModel", | 
|  | 51 | +                "attributes": { | 
|  | 52 | +                    format_value("test_attribute", format_field_names): "test-value" | 
|  | 53 | +                }, | 
|  | 54 | +                "relationships": { | 
|  | 55 | +                    format_value("test_relationship", format_field_names): { | 
|  | 56 | +                        "data": {"type": "TestRelationship", "id": "123"} | 
|  | 57 | +                    } | 
|  | 58 | +                }, | 
|  | 59 | +            } | 
|  | 60 | +        } | 
|  | 61 | + | 
|  | 62 | +        result = parse(data) | 
|  | 63 | +        assert result == { | 
|  | 64 | +            "id": "123", | 
|  | 65 | +            "test_attribute": "test-value", | 
|  | 66 | +            "test_relationship": {"id": "123", "type": "TestRelationship"}, | 
|  | 67 | +        } | 
|  | 68 | + | 
|  | 69 | +    def test_parse_extracts_meta(self, parse): | 
|  | 70 | +        data = { | 
|  | 71 | +            "data": { | 
|  | 72 | +                "type": "BasicModel", | 
|  | 73 | +            }, | 
|  | 74 | +            "meta": {"random_key": "random_value"}, | 
|  | 75 | +        } | 
|  | 76 | + | 
|  | 77 | +        result = parse(data) | 
|  | 78 | +        assert result["_meta"] == data["meta"] | 
|  | 79 | + | 
|  | 80 | +    def test_parse_preserves_json_value_field_names(self, settings, parse): | 
|  | 81 | +        settings.JSON_API_FORMAT_FIELD_NAMES = "dasherize" | 
|  | 82 | + | 
|  | 83 | +        data = { | 
|  | 84 | +            "data": { | 
|  | 85 | +                "type": "BasicModel", | 
|  | 86 | +                "attributes": {"json-value": {"JsonKey": "JsonValue"}}, | 
|  | 87 | +            }, | 
|  | 88 | +        } | 
|  | 89 | + | 
|  | 90 | +        result = parse(data) | 
|  | 91 | +        assert result["json_value"] == {"JsonKey": "JsonValue"} | 
|  | 92 | + | 
|  | 93 | +    def test_parse_raises_error_on_empty_data(self, parse): | 
|  | 94 | +        data = [] | 
|  | 95 | + | 
|  | 96 | +        with pytest.raises(ParseError) as excinfo: | 
|  | 97 | +            parse(data) | 
|  | 98 | +        assert "Received document does not contain primary data" == str(excinfo.value) | 
|  | 99 | + | 
|  | 100 | +    def test_parse_fails_on_list_of_objects(self, parse): | 
|  | 101 | +        data = { | 
|  | 102 | +            "data": [ | 
|  | 103 | +                { | 
|  | 104 | +                    "type": "BasicModel", | 
|  | 105 | +                    "attributes": {"json-value": {"JsonKey": "JsonValue"}}, | 
|  | 106 | +                } | 
|  | 107 | +            ], | 
|  | 108 | +        } | 
|  | 109 | + | 
|  | 110 | +        with pytest.raises(ParseError) as excinfo: | 
|  | 111 | +            parse(data) | 
|  | 112 | + | 
|  | 113 | +        assert "Received data is not a valid JSONAPI Resource Identifier Object" == str( | 
|  | 114 | +            excinfo.value | 
|  | 115 | +        ) | 
|  | 116 | + | 
|  | 117 | +    def test_parse_fails_when_id_is_missing_on_patch(self, rf, parse, parser_context): | 
|  | 118 | +        parser_context["request"] = rf.patch("/") | 
|  | 119 | +        data = { | 
|  | 120 | +            "data": { | 
|  | 121 | +                "type": "BasicModel", | 
|  | 122 | +            }, | 
|  | 123 | +        } | 
|  | 124 | + | 
|  | 125 | +        with pytest.raises(ParseError) as excinfo: | 
|  | 126 | +            parse(data) | 
|  | 127 | + | 
|  | 128 | +        assert "The resource identifier object must contain an 'id' member" == str( | 
|  | 129 | +            excinfo.value | 
|  | 130 | +        ) | 
0 commit comments