def test_custom_validation(): def optional(t): def do(elem): if elem is None: return elem return Type(elem) return do types = { "articles": { "title": optional(str), }, } response = { "data": { "type": "articles", "id": "1", "attributes": { "title": None }, }, } validator = Validator(top="articles", types=types) result = validator.validate(response) assert result["data"]["title"] is None
def test_include_args(): types = { "articles": { "author": Rel("people"), "comments": Rel(["comments"]) }, "people": { "articles": Rel(["articles"]), "comments": Rel(["comments"]), }, "comments": { "author": Rel("people") } } include = { "author": { "articles": {}, "comments": {}, }, "comments": {} } validator = Validator("articles", types, include=include) args = validator.include_args() assert set(args) == {"author", "author.articles", "author.comments", "comments"}
def test_include_null_field(): types = { "articles": { "author": Rel("people"), }, "people": { "foo": Type(str), }, } include = { "author": {}, } response = { "data": { "type": "articles", "id": "1", "relationships": { "author": { "links": "foobar", "data": None }, }, } } validator = Validator("articles", types, include=include) msg = validator.validate(deepcopy(response)) assert msg["data"]["author"]["data"] is None
def test_include_field_without_data(): types = { "articles": { "author": Rel("people"), }, "people": { "foo": Type(str), }, } include = { "author": {}, } response = { "data": { "type": "articles", "id": "1", "relationships": { "author": { "links": "foobar" }, }, } } validator = Validator("articles", types) validator.validate(deepcopy(response)) validator = Validator("articles", types, include=include) with pytest.raises(ValidationError): validator.validate(deepcopy(response))
def test_bad_rel_list_type(): types = { "articles": { "comments": Rel(["bar"]), }, "foo": {}, "bar": {}, } correct_types = { "articles": { "comments": Rel(["foo"]), }, "foo": {}, "bar": {}, } response = { "data": { "type": "articles", "id": "1", "relationships": { "comments": { "data": [{ "id": "1", "type": "foo", }] } }, }, } validator = Validator(top="articles", types=types) with pytest.raises(ValidationError): validator.validate(response) validator = Validator(top="articles", types=correct_types) validator.validate(response)
def test_bad_field_type(): types = { "articles": { "title": Type(str), }, } response1 = { "data": { "type": "articles", "id": "1", "attributes": { "title": ["Hello", "world"] }, }, } validator = Validator(top="articles", types=types) with pytest.raises(ValidationError): validator.validate(response1) response2 = { "data": { "type": "articles", "id": "1", "attributes": { "title": None }, }, } validator = Validator(top="articles", types=types) with pytest.raises(ValidationError): validator.validate(response2)
def test_all_is_well(): validator = Validator(top=["articles"], types=types, include=include) mcopy = deepcopy(response) mcopy = validator.validate(mcopy) author_obj = mcopy["data"][0] assert author_obj["title"] == author_obj[".attributes"]["title"] assert author_obj["author"] == author_obj[".relationships"]["author"] assert author_obj["comments"] == author_obj[".relationships"]["comments"] assert author_obj["author"]["data"]["firstName"] == "Dan" assert author_obj["comments"]["data"][0]["body"] == "First!" assert mcopy["links"] == response["links"]
def test_fields_args(): types = { "articles": { "title": Type(str), "comments": Rel(["comments"]) }, "comments": { "foo": Type(str), "bar": Type(str), } } fields = {"articles": ["comments"], "comments": ["foo", "bar"]} validator = Validator(top="foo", types=types, fields=fields) attrs = validator.fields_args() assert set(attrs) == { "fields[articles]=comments", "fields[comments]=foo,bar" }
def test_fields_missing_field(): types = { "articles": { "title": Type(str), "body": Type(str), }, } response = { "data": { "type": "articles", "id": "1", "attributes": { "body": "JSON:API paints my bikeshed!" }, }, } fields = {"articles": ["title"]} validator = Validator(top="articles", types=types, fields=fields) with pytest.raises(ValidationError): validator.validate(response)
def test_rel_fields(): types = { "articles": { "title": Type(str), "comments": Rel(["comments"]) }, "comments": { "foo": Type(str), "bar": Type(str), } } response = { "data": { "type": "articles", "id": "1", "relationships": { "comments": { "data": [{ "id": "1", "type": "comments", }] } }, }, "included": [{ "type": "comments", "id": "1", "attributes": { "foo": "baz" } }] } fields = {"articles": ["comments"], "comments": ["foo"]} validator = Validator(top="articles", types=types, fields=fields) res = validator.validate(response) assert res["data"]["comments"]["data"][0]["foo"] == "baz"
def test_fields_work(): types = { "articles": { "title": Type(str), "body": Type(str), }, } response = { "data": { "type": "articles", "id": "1", "attributes": { "title": "JSON:API paints my bikeshed!" }, }, } fields = {"articles": ["title"]} validator = Validator(top="articles", types=types, fields=fields) res = validator.validate(response) assert "title" in res["data"]
def test_null_relation(): types = { "articles": { "comments": Rel("bar"), }, "foo": {}, "bar": {}, } response = { "data": { "type": "articles", "id": "1", "relationships": { "comments": { "data": None } }, }, } validator = Validator("articles", types) msg = validator.validate(response) assert msg["data"]["comments"]["data"] is None
def test_relation_without_data(): types = { "articles": { "comments": Rel(["bar"]), }, "foo": {}, "bar": {}, } response = { "data": { "type": "articles", "id": "1", "relationships": { "comments": { "links": "http://foo.bar" } }, }, } validator = Validator("articles", types) msg = validator.validate(response) assert "links" in msg["data"]["comments"] assert "data" not in msg["data"]["comments"]
def test_missing_type(): types = { "articles": { "title": Type(str), }, } response = { "data": { "type": "articles", "id": "1", "attributes": { "title": "JSON:API paints my bikeshed!" }, }, "included": [{ "type": "things", "id": "1", }] } validator = Validator(top="articles", types=types) with pytest.raises(ValidationError): validator.validate(response) other_types = {"things": {}} validator = Validator(top="articles", types=other_types) with pytest.raises(ValidationError): validator.validate(response) full_types = { "articles": { "title": Type(str), }, "things": {} } validator = Validator(top="articles", types=full_types) validator.validate(response)
def test_missing_fields(): types = { "articles": { "title": Type(str), }, } response1 = { "data": { "type": "articles", "id": "1", "attributes": {}, }, } validator = Validator(top="articles", types=types) with pytest.raises(ValidationError): validator.validate(response1) response2 = { "data": { "type": "articles", "id": "1", }, } validator = Validator(top="articles", types=types) with pytest.raises(ValidationError): validator.validate(response2) types_rel = {"articles": {"comments": Rel("comments")}, "comments": {}} response1_rel = { "data": { "type": "articles", "id": "1", }, } validator = Validator(top="articles", types=types_rel) with pytest.raises(ValidationError): validator.validate(response1_rel) response2_rel = { "data": { "type": "articles", "id": "1", "relationships": { "things": { "data": { "type": "comments", "id": "1" } } } }, } validator = Validator(top="articles", types=types_rel) with pytest.raises(ValidationError): validator.validate(response2_rel)
def test_bad_top_type(): types = { "articles": { "title": Type(str), }, "people": { "firstName": Type(str), } } response = { "data": { "type": "articles", "id": "1", "attributes": { "title": "JSON:API paints my bikeshed!" }, }, } validator = Validator(top="people", types=types) with pytest.raises(ValidationError): validator.validate(response) validator = Validator(top=["people"], types=types) with pytest.raises(ValidationError): validator.validate(response) validator = Validator(top=["articles"], types=types) with pytest.raises(ValidationError): validator.validate(response) validator = Validator(top="articles", types=types) validator.validate(response) response2 = { "data": [{ "type": "articles", "id": "1", "attributes": { "title": "JSON:API paints my bikeshed!" }, }], } validator = Validator(top="articles", types=types) with pytest.raises(ValidationError): validator.validate(response2) validator = Validator(top=["people"], types=types) with pytest.raises(ValidationError): validator.validate(response2)
def test_missing_includes(): types = { "articles": { "author": Rel("people"), "comments": Rel(["comments"]) }, "people": { "foo": Type(str), }, "comments": { "foo": Type(str), } } include = { "author": {}, "comments": {}, } response_data = { "type": "articles", "id": "1", "relationships": { "author": { "data": { "id": "1", "type": "people", } }, "comments": { "data": [{ "id": "1", "type": "comments", }] } }, } response_1 = { "data": response_data, "included": [{ "id": "1", "type": "comments", "attributes": { "foo": "bar" } }] } response_2 = { "data": response_data, "included": [{ "id": "1", "type": "people", "attributes": { "foo": "bar" } }] } response_3 = { "data": response_data, "included": [ { "id": "1", "type": "people", "attributes": { "foo": "bar" } }, { "id": "1", "type": "comments", "attributes": { "foo": "bar" } } ] } validator = Validator("articles", types, include=include) with pytest.raises(ValidationError): validator.validate(deepcopy(response_1)) with pytest.raises(ValidationError): validator.validate(deepcopy(response_2)) validator.validate(deepcopy(response_3))