Skip to content

Commit

Permalink
WIP - JSON
Browse files Browse the repository at this point in the history
  • Loading branch information
kurtmckee committed Sep 22, 2023
1 parent e2060e9 commit 02921c9
Show file tree
Hide file tree
Showing 38 changed files with 454 additions and 181 deletions.
369 changes: 252 additions & 117 deletions feedparser/parsers/json.py

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion tests/json/author-name-missing-with-avatar.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"__description": "author.name: `name` key missing, but `avatar` present",
"__tests": [
"'author' not in feed",
"feed['author'] == 'https://domain.example/i.jpeg'",
"len(feed['author_detail'].keys()) == 1",
"'name' not in feed['author_detail']",
"len(feed['authors'][0].keys()) == 1",
Expand Down
13 changes: 13 additions & 0 deletions tests/json/author-name-missing-with-mailto-url.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"__description": "author.name: `name` key missing, but mailto: `url` present",
"__tests": [
"feed['author'] == 'user@domain.example'",
"len(feed['author_detail'].keys()) == 1",
"'name' not in feed['author_detail']",
"len(feed['authors'][0].keys()) == 1",
"'name' not in feed['authors'][0]"
],
"author": {
"url": "mailto:user@domain.example?subject=Hello"
}
}
2 changes: 1 addition & 1 deletion tests/json/author-name-missing-with-url.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"__description": "author.name: `name` key missing, but `url` present",
"__tests": [
"'author' not in feed",
"feed['author'] == 'https://domain.example/'",
"len(feed['author_detail'].keys()) == 1",
"'name' not in feed['author_detail']",
"len(feed['authors'][0].keys()) == 1",
Expand Down
6 changes: 3 additions & 3 deletions tests/json/author-url-mailto-with-parameters.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
{
"__description": "author.url: `mailto:` URI with parameters",
"__tests": [
"'url' not in feed['author_detail']",
"feed['author_detail']['href'] == 'mailto:user@domain.example?subject=Feed'",
"'url' not in feed['authors'][0]",
"feed['authors'][0]['href'] == 'mailto:user@domain.example?subject=Feed'"
"feed['author_detail']['email'] == 'user@domain.example'",
"feed['authors'][0]['href'] == 'mailto:user@domain.example?subject=Feed'",
"feed['authors'][0]['email'] == 'user@domain.example'"
],
"author": {
"name": "abc",
Expand Down
4 changes: 2 additions & 2 deletions tests/json/author-url-mailto.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
{
"__description": "author.url: `mailto:` URI",
"__tests": [
"'url' not in feed['author_detail']",
"feed['author_detail']['href'] == 'mailto:user@domain.example'",
"feed['author_detail']['email'] == 'user@domain.example'",
"'url' not in feed['authors'][0]",
"feed['authors'][0]['href'] == 'mailto:user@domain.example'",
"feed['authors'][0]['email'] == 'user@domain.example'"
],
"author": {
Expand Down
2 changes: 1 addition & 1 deletion tests/json/description-blank.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"feed['subtitle'] == ''",
"feed['subtitle_detail']['value'] == ''"
],
"description": " "
"description": ""
}
10 changes: 10 additions & 0 deletions tests/json/description-html-is-ignored.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"__description": "description: html must be ignored",
"__tests": [
"feed['subtitle'] == \"<blink><script>alert('abc');</script></blink>\"",
"len(feed['subtitle_detail']) == 2",
"feed['subtitle_detail']['type'] == 'text/plain'",
"feed['subtitle_detail']['value'] == \"<blink><script>alert('abc');</script></blink>\""
],
"description": "<blink><script>alert('abc');</script></blink>"
}
10 changes: 0 additions & 10 deletions tests/json/description-html.json

This file was deleted.

2 changes: 1 addition & 1 deletion tests/json/expired-boolean-false.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"__description": "expired: boolean false means 'false'",
"__tests": [
"feed['complete'] is False"
"feed['expired'] is False"
],
"expired": false
}
2 changes: 1 addition & 1 deletion tests/json/expired-boolean-true.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"__description": "expired: boolean true means 'true'",
"__tests": [
"feed['complete'] is True"
"feed['expired'] is True"
],
"expired": true
}
7 changes: 7 additions & 0 deletions tests/json/expired-int-1.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"__description": "expired: integer 1 means false",
"__tests": [
"feed['expired'] is False"
],
"expired": 1
}
2 changes: 1 addition & 1 deletion tests/json/expired-key-not-present.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"__description": "expired: should not exist if not present in feed",
"__tests": [
"'complete' not in feed"
"'expired' not in feed"
]
}
7 changes: 7 additions & 0 deletions tests/json/expired-null.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"__description": "expired: an explicit null value means false",
"__tests": [
"feed['expired'] is False"
],
"expired": null
}
2 changes: 1 addition & 1 deletion tests/json/expired-string-true.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"__description": "expired: string 'true' is not 'true'",
"__tests": [
"feed['complete'] is False"
"feed['expired'] is False"
],
"expired": "true"
}
2 changes: 1 addition & 1 deletion tests/json/favicon-blank.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"__tests": [
"feed['icon'] == ''"
],
"favicon": " "
"favicon": ""
}
2 changes: 1 addition & 1 deletion tests/json/feed_url-blank.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"feed['id'] == ''",
"feed['links'][0]['href'] == ''"
],
"feed_url": " "
"feed_url": ""
}
2 changes: 1 addition & 1 deletion tests/json/home_page_url-blank.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"__tests": [
"feed.link == ''"
],
"home_page_url": " "
"home_page_url": ""
}
2 changes: 1 addition & 1 deletion tests/json/icon-blank.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"__tests": [
"feed['image']['href'] == ''"
],
"icon": " "
"icon": ""
}
14 changes: 14 additions & 0 deletions tests/json/items-title-blank.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"__description": "items.title: blank values are not lost",
"__tests": [
"entries[0]['title'] == ''",
"len(entries[0]['title_detail'].keys()) == 2",
"entries[0]['title_detail']['value'] == ''",
"entries[0]['title_detail']['type'] == 'text/plain'"
],
"items": [
{
"title": ""
}
]
}
14 changes: 14 additions & 0 deletions tests/json/items-title-html-is-ignored.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"__description": "items.title: html must be ignored",
"__tests": [
"entries[0]['title'] == \"<blink><script>alert('abc');</script></blink>\"",
"len(entries[0]['title_detail']) == 2",
"entries[0]['title_detail']['value'] == \"<blink><script>alert('abc');</script></blink>\"",
"entries[0]['title_detail']['type'] == 'text/plain'"
],
"items": [
{
"title": "<blink><script>alert('abc');</script></blink>"
}
]
}
12 changes: 12 additions & 0 deletions tests/json/items-title-value-type-incorrect.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"__description": "items.title: value is not a string",
"__tests": [
"'title' not in entries[0]",
"'title_detail' not in entries[0]"
],
"items": [
{
"title": [1, 2, 3]
}
]
}
12 changes: 12 additions & 0 deletions tests/json/items-title-whitespace.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"__description": "items.title: whitespace must be stripped",
"__tests": [
"entries[0]['title'] == 'abc'",
"entries[0]['title_detail']['value'] == 'abc'"
],
"items": [
{
"title": " abc "
}
]
}
14 changes: 14 additions & 0 deletions tests/json/items-title.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{
"__description": "items.title: valid value",
"__tests": [
"entries[0]['title'] == 'abc'",
"len(entries[0]['title_detail'].keys()) == 2",
"entries[0]['title_detail']['value'] == 'abc'",
"entries[0]['title_detail']['type'] == 'text/plain'"
],
"items": [
{
"title": "abc"
}
]
}
12 changes: 12 additions & 0 deletions tests/json/items-url-blank.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"__description": "items.url: blank values are not lost",
"__tests": [
"entries[0]['link'] == ''",
"entries[0]['links'][0]['href'] == ''"
],
"items": [
{
"url": ""
}
]
}
17 changes: 17 additions & 0 deletions tests/json/items-url-with-title.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"__description": "items.url: entry has a title",
"__tests": [
"entries[0]['link'] == 'https://domain.example/entry'",
"len(entries[0]['links']) == 1",
"len(entries[0]['links'][0].keys()) == 3",
"entries[0]['links'][0]['rel'] == 'self'",
"entries[0]['links'][0]['href'] == 'https://domain.example/entry'",
"entries[0]['links'][0]['title'] == 'abc'"
],
"items": [
{
"title": "abc",
"url": "https://domain.example/entry"
}
]
}
15 changes: 15 additions & 0 deletions tests/json/items-url-without-title.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"__description": "items.url: entry has no title",
"__tests": [
"entries[0]['link'] == 'https://domain.example/entry'",
"len(entries[0]['links']) == 1",
"len(entries[0]['links'][0].keys()) == 2",
"entries[0]['links'][0]['rel'] == 'self'",
"entries[0]['links'][0]['href'] == 'https://domain.example/entry'"
],
"items": [
{
"url": "https://domain.example/entry"
}
]
}
11 changes: 0 additions & 11 deletions tests/json/items-url.json

This file was deleted.

2 changes: 1 addition & 1 deletion tests/json/next_url-blank.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"__tests": [
"feed['links'][0]['href'] == ''"
],
"next_url": " "
"next_url": ""
}
2 changes: 1 addition & 1 deletion tests/json/title-blank.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"__tests": [
"feed['title'] == ''"
],
"title": " "
"title": ""
}
10 changes: 10 additions & 0 deletions tests/json/title-html-is-ignored.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"__description": "title: html must be ignored",
"__tests": [
"feed['title'] == \"<blink><script>alert('abc');</script></blink>\"",
"len(feed['title_detail'].keys()) == 2",
"feed['title_detail']['type'] == 'text/plain'",
"feed['title_detail']['value'] == \"<blink><script>alert('abc');</script></blink>\""
],
"title": "<blink><script>alert('abc');</script></blink>"
}
10 changes: 0 additions & 10 deletions tests/json/title-html.json

This file was deleted.

2 changes: 1 addition & 1 deletion tests/json/user_comment-blank.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@
"feed['info'] == ''",
"feed['info_detail']['value'] == ''"
],
"user_comment": " "
"user_comment": ""
}
10 changes: 10 additions & 0 deletions tests/json/user_comment-html-is-ignored.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"__description": "user_comment: html must be ignored",
"__tests": [
"feed['info'] == \"<blink><script>alert('abc');</script></blink>\"",
"len(feed['info_detail']) == 2",
"feed['info_detail']['type'] == 'text/plain'",
"feed['info_detail']['value'] == \"<blink><script>alert('abc');</script></blink>\""
],
"user_comment": "<blink><script>alert('abc');</script></blink>"
}
10 changes: 0 additions & 10 deletions tests/json/user_comment-html.json

This file was deleted.

4 changes: 2 additions & 2 deletions tests/json/user_comment-text.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
"__tests": [
"feed['info'] == 'abc\ud83d\ude0e\ud83c\udf34\ud83c\udfb6def'",
"len(feed['info_detail'].keys()) == 2",
"feed['info_detail']['value'] == 'abc\ud83d\ude0e\ud83c\udf34\ud83c\udfb6def'",
"feed['info_detail']['type'] == 'text/plain'"
"feed['info_detail']['type'] == 'text/plain'",
"feed['info_detail']['value'] == 'abc\ud83d\ude0e\ud83c\udf34\ud83c\udfb6def'"
],
"user_comment": "abc😎🌴🎶def"
}
2 changes: 1 addition & 1 deletion tests/json/version-blank.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
"__tests": [
"version == 'json'"
],
"version": " "
"version": ""
}
14 changes: 13 additions & 1 deletion tests/test_json.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,17 @@ def test_json(path):
data = json.loads(text)
result = feedparser.parse(text, sanitize_html=False)
for test_string in data["__tests"]:
assert eval(test_string, result, locals()), test_string
assert eval(test_string, None, result), test_string

# Verify that all dicts are instances of FeedParserDict.
dicts: list[tuple[str, dict]] = [("top level", result)]
while dicts:
key, value = dicts.pop()
assert isinstance(value, feedparser.FeedParserDict), f"{key} is just a dict"
dicts.extend(
(k, v)
for k, v in value.items()
if isinstance(v, dict) and k != "namespaces" and k != "headers"
)

assert result["bozo"] is False, result["bozo_exception"]

0 comments on commit 02921c9

Please sign in to comment.