2017-10-28 19:18:34 +00:00
|
|
|
# This file is part of Supysonic.
|
|
|
|
# Supysonic is a Python implementation of the Subsonic server API.
|
|
|
|
#
|
2018-01-05 23:33:45 +00:00
|
|
|
# Copyright (C) 2017-2018 Alban 'spl0k' Féron
|
2017-10-28 19:18:34 +00:00
|
|
|
#
|
|
|
|
# Distributed under terms of the GNU AGPLv3 license.
|
|
|
|
|
2017-11-27 21:30:13 +00:00
|
|
|
import unittest
|
2018-01-21 21:02:32 +00:00
|
|
|
import flask.json
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
from xml.etree import ElementTree
|
|
|
|
|
2018-02-11 11:40:10 +00:00
|
|
|
from supysonic.api.formatters import JSONFormatter, JSONPFormatter, XMLFormatter
|
2018-01-08 22:13:50 +00:00
|
|
|
|
2017-11-27 21:30:13 +00:00
|
|
|
from ..testbase import TestBase
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
|
2020-11-22 15:12:14 +00:00
|
|
|
class UnwrapperMixin:
|
2018-02-11 11:40:10 +00:00
|
|
|
def make_response(self, elem, data):
|
|
|
|
with self.request_context():
|
2020-11-22 15:12:14 +00:00
|
|
|
rv = super().make_response(elem, data)
|
2019-06-29 15:25:44 +00:00
|
|
|
return rv.get_data(as_text=True)
|
2017-11-27 21:30:13 +00:00
|
|
|
|
2018-02-11 11:40:10 +00:00
|
|
|
@staticmethod
|
|
|
|
def create_from(cls):
|
|
|
|
class Unwrapper(UnwrapperMixin, cls):
|
|
|
|
pass
|
2019-06-29 15:25:44 +00:00
|
|
|
|
2018-02-11 11:40:10 +00:00
|
|
|
return Unwrapper
|
2018-01-27 14:18:44 +00:00
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
|
2018-02-11 11:40:10 +00:00
|
|
|
class ResponseHelperJsonTestCase(TestBase, UnwrapperMixin.create_from(JSONFormatter)):
|
|
|
|
def make_response(self, elem, data):
|
2020-11-22 15:12:14 +00:00
|
|
|
rv = super().make_response(elem, data)
|
2018-02-11 11:40:10 +00:00
|
|
|
return flask.json.loads(rv)
|
2018-01-27 14:18:44 +00:00
|
|
|
|
2018-02-11 11:40:10 +00:00
|
|
|
def process_and_extract(self, d):
|
2019-06-29 15:25:44 +00:00
|
|
|
return self.make_response("tag", d)["subsonic-response"]["tag"]
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
def test_basic(self):
|
2018-02-11 11:40:10 +00:00
|
|
|
empty = self.empty
|
2017-10-28 19:18:34 +00:00
|
|
|
self.assertEqual(len(empty), 1)
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertIn("subsonic-response", empty)
|
|
|
|
self.assertIsInstance(empty["subsonic-response"], dict)
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
resp = empty["subsonic-response"]
|
2017-10-28 19:18:34 +00:00
|
|
|
self.assertEqual(len(resp), 2)
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertIn("status", resp)
|
|
|
|
self.assertIn("version", resp)
|
|
|
|
self.assertEqual(resp["status"], "ok")
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
resp = self.error(0, "message")["subsonic-response"]
|
|
|
|
self.assertEqual(resp["status"], "failed")
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
some_dict = {"intValue": 2, "someString": "Hello world!"}
|
2017-10-28 19:18:34 +00:00
|
|
|
resp = self.process_and_extract(some_dict)
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertIn("intValue", resp)
|
|
|
|
self.assertIn("someString", resp)
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
def test_lists(self):
|
2019-06-29 15:25:44 +00:00
|
|
|
resp = self.process_and_extract({"someList": [2, 4, 8, 16], "emptyList": []})
|
|
|
|
self.assertIn("someList", resp)
|
|
|
|
self.assertNotIn("emptyList", resp)
|
|
|
|
self.assertListEqual(resp["someList"], [2, 4, 8, 16])
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
def test_dicts(self):
|
2019-06-29 15:25:44 +00:00
|
|
|
resp = self.process_and_extract({"dict": {"s": "Blah", "i": 20}, "empty": {}})
|
|
|
|
self.assertIn("dict", resp)
|
|
|
|
self.assertIn("empty", resp)
|
|
|
|
self.assertDictEqual(resp["dict"], {"s": "Blah", "i": 20})
|
|
|
|
self.assertDictEqual(resp["empty"], {})
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
def test_nesting(self):
|
2019-06-29 15:25:44 +00:00
|
|
|
resp = self.process_and_extract(
|
|
|
|
{
|
|
|
|
"dict": {
|
|
|
|
"value": "hey look! a string",
|
|
|
|
"list": [1, 2, 3],
|
|
|
|
"emptyList": [],
|
|
|
|
"subdict": {"a": "A"},
|
|
|
|
},
|
|
|
|
"list": [{"b": "B"}, {"c": "C"}, [4, 5, 6], "final string"],
|
|
|
|
}
|
|
|
|
)
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2018-02-11 11:40:10 +00:00
|
|
|
self.assertEqual(len(resp), 2)
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertIn("dict", resp)
|
|
|
|
self.assertIn("list", resp)
|
|
|
|
|
2020-11-29 16:24:28 +00:00
|
|
|
dct = resp["dict"]
|
|
|
|
lst = resp["list"]
|
|
|
|
|
|
|
|
self.assertIn("value", dct)
|
|
|
|
self.assertIn("list", dct)
|
|
|
|
self.assertNotIn("emptyList", dct)
|
|
|
|
self.assertIn("subdict", dct)
|
|
|
|
self.assertIsInstance(dct["value"], str)
|
|
|
|
self.assertIsInstance(dct["list"], list)
|
|
|
|
self.assertIsInstance(dct["subdict"], dict)
|
|
|
|
|
|
|
|
self.assertEqual(lst, [{"b": "B"}, {"c": "C"}, [4, 5, 6], "final string"])
|
2019-06-29 15:25:44 +00:00
|
|
|
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2018-02-11 11:40:10 +00:00
|
|
|
class ResponseHelperJsonpTestCase(TestBase, UnwrapperMixin.create_from(JSONPFormatter)):
|
2017-10-28 19:18:34 +00:00
|
|
|
def test_basic(self):
|
2019-06-29 15:25:44 +00:00
|
|
|
self._JSONPFormatter__callback = "callback" # hacky
|
2018-02-11 11:40:10 +00:00
|
|
|
result = self.empty
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertTrue(result.startswith("callback({"))
|
|
|
|
self.assertTrue(result.endswith("})"))
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2018-01-21 21:02:32 +00:00
|
|
|
json = flask.json.loads(result[9:-1])
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertIn("subsonic-response", json)
|
|
|
|
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2018-02-11 11:40:10 +00:00
|
|
|
class ResponseHelperXMLTestCase(TestBase, UnwrapperMixin.create_from(XMLFormatter)):
|
|
|
|
def make_response(self, elem, data):
|
2020-11-22 15:12:14 +00:00
|
|
|
xml = super().make_response(elem, data)
|
2019-06-29 15:25:44 +00:00
|
|
|
xml = xml.replace('xmlns="http://subsonic.org/restapi"', "")
|
2017-10-28 19:18:34 +00:00
|
|
|
root = ElementTree.fromstring(xml)
|
|
|
|
return root
|
|
|
|
|
2018-02-11 11:40:10 +00:00
|
|
|
def process_and_extract(self, d):
|
2019-06-29 15:25:44 +00:00
|
|
|
rv = self.make_response("tag", d)
|
|
|
|
return rv.find("tag")
|
2018-02-11 11:40:10 +00:00
|
|
|
|
2017-10-28 19:18:34 +00:00
|
|
|
def assertAttributesMatchDict(self, elem, d):
|
2019-06-29 15:25:44 +00:00
|
|
|
d = {k: str(v) for k, v in d.items()}
|
2017-10-28 19:18:34 +00:00
|
|
|
self.assertDictEqual(elem.attrib, d)
|
|
|
|
|
|
|
|
def test_root(self):
|
2020-11-22 15:12:14 +00:00
|
|
|
xml = super().make_response("tag", {})
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertIn("<subsonic-response ", xml)
|
2018-01-08 22:13:50 +00:00
|
|
|
self.assertIn('xmlns="http://subsonic.org/restapi"', xml)
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertTrue(xml.strip().endswith("</subsonic-response>"))
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
def test_basic(self):
|
2018-02-11 11:40:10 +00:00
|
|
|
empty = self.empty
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertIsNotNone(empty.find(".[@version]"))
|
2018-01-08 22:13:50 +00:00
|
|
|
self.assertIsNotNone(empty.find(".[@status='ok']"))
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
resp = self.error(0, "message")
|
2018-01-08 22:13:50 +00:00
|
|
|
self.assertIsNotNone(resp.find(".[@status='failed']"))
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
some_dict = {"intValue": 2, "someString": "Hello world!"}
|
2018-02-11 11:40:10 +00:00
|
|
|
resp = self.process_and_extract(some_dict)
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertIsNotNone(resp.find(".[@intValue]"))
|
|
|
|
self.assertIsNotNone(resp.find(".[@someString]"))
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
def test_lists(self):
|
2019-06-29 15:25:44 +00:00
|
|
|
resp = self.process_and_extract({"someList": [2, 4, 8, 16], "emptyList": []})
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
elems = resp.findall("./someList")
|
2017-10-28 19:18:34 +00:00
|
|
|
self.assertEqual(len(elems), 4)
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertIsNone(resp.find("./emptyList"))
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
for e, i in zip(elems, [2, 4, 8, 16]):
|
2017-10-28 19:18:34 +00:00
|
|
|
self.assertEqual(int(e.text), i)
|
|
|
|
|
|
|
|
def test_dicts(self):
|
2019-06-29 15:25:44 +00:00
|
|
|
resp = self.process_and_extract({"dict": {"s": "Blah", "i": 20}, "empty": {}})
|
2017-10-28 19:18:34 +00:00
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
d = resp.find("./dict")
|
2017-10-28 19:18:34 +00:00
|
|
|
self.assertIsNotNone(d)
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertIsNotNone(resp.find("./empty"))
|
|
|
|
self.assertAttributesMatchDict(d, {"s": "Blah", "i": 20})
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
def test_nesting(self):
|
2019-06-29 15:25:44 +00:00
|
|
|
resp = self.process_and_extract(
|
|
|
|
{
|
|
|
|
"dict": {
|
|
|
|
"somevalue": "hey look! a string",
|
|
|
|
"list": [1, 2, 3],
|
|
|
|
"emptyList": [],
|
|
|
|
"subdict": {"a": "A"},
|
|
|
|
},
|
|
|
|
"list": [{"b": "B"}, {"c": "C"}, "final string"],
|
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
self.assertEqual(len(resp), 4) # 'dict' and 3 'list's
|
|
|
|
|
|
|
|
d = resp.find("./dict")
|
|
|
|
lists = resp.findall("./list")
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
self.assertIsNotNone(d)
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertAttributesMatchDict(d, {"somevalue": "hey look! a string"})
|
|
|
|
self.assertEqual(len(d.findall("./list")), 3)
|
|
|
|
self.assertEqual(len(d.findall("./emptyList")), 0)
|
|
|
|
self.assertIsNotNone(d.find("./subdict"))
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
self.assertEqual(len(lists), 3)
|
2019-06-29 15:25:44 +00:00
|
|
|
self.assertAttributesMatchDict(lists[0], {"b": "B"})
|
|
|
|
self.assertAttributesMatchDict(lists[1], {"c": "C"})
|
|
|
|
self.assertEqual(lists[2].text, "final string")
|
|
|
|
|
2017-10-28 19:18:34 +00:00
|
|
|
|
|
|
|
def suite():
|
|
|
|
suite = unittest.TestSuite()
|
|
|
|
|
|
|
|
suite.addTest(unittest.makeSuite(ResponseHelperJsonTestCase))
|
|
|
|
suite.addTest(unittest.makeSuite(ResponseHelperJsonpTestCase))
|
|
|
|
suite.addTest(unittest.makeSuite(ResponseHelperXMLTestCase))
|
|
|
|
|
|
|
|
return suite
|
|
|
|
|
|
|
|
|
2019-06-29 15:25:44 +00:00
|
|
|
if __name__ == "__main__":
|
|
|
|
unittest.main()
|