190 lines
6.2 KiB
Python
190 lines
6.2 KiB
Python
from __future__ import annotations
|
|
|
|
import importlib.util
|
|
import os
|
|
import sys
|
|
import types
|
|
import unittest
|
|
from pathlib import Path
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def install_twisted_stub():
|
|
if "twisted" in sys.modules:
|
|
return
|
|
if importlib.util.find_spec("twisted") is not None:
|
|
return
|
|
twisted = types.ModuleType("twisted")
|
|
web = types.ModuleType("twisted.web")
|
|
resource_mod = types.ModuleType("twisted.web.resource")
|
|
static_mod = types.ModuleType("twisted.web.static")
|
|
|
|
class Resource:
|
|
isLeaf = False
|
|
def __init__(self):
|
|
self.children = {}
|
|
def putChild(self, name, child):
|
|
if not isinstance(name, bytes):
|
|
raise TypeError("child names must be bytes")
|
|
self.children[name] = child
|
|
def getChild(self, name, request):
|
|
return self
|
|
|
|
class File(Resource):
|
|
def __init__(self, path):
|
|
super().__init__(); self.path = path
|
|
def render(self, request):
|
|
p = Path(self.path)
|
|
return p.read_bytes() if p.is_file() else b""
|
|
|
|
resource_mod.Resource = Resource
|
|
static_mod.File = File
|
|
web.resource = resource_mod
|
|
web.static = static_mod
|
|
twisted.web = web
|
|
sys.modules.update({
|
|
"twisted": twisted,
|
|
"twisted.web": web,
|
|
"twisted.web.resource": resource_mod,
|
|
"twisted.web.static": static_mod,
|
|
})
|
|
|
|
|
|
class ResourceTests(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
install_twisted_stub()
|
|
cls.old_cwd = Path.cwd()
|
|
os.chdir(ROOT)
|
|
import hatena
|
|
cls.root = hatena.Setup()
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
os.chdir(cls.old_cwd)
|
|
|
|
def test_dsi_tree_loads(self):
|
|
region = self.root.dsResource.region
|
|
for key in [b"index.ugo", b"index.uls", b"allflipnotes.ugo", b"allflipnotes.uls", b"movie", b"creator", b"comment", b"ch", b"sa"]:
|
|
self.assertIn(key, region.children)
|
|
|
|
def test_generated_icons_are_dsi_sized(self):
|
|
image_dir = ROOT / "hatenadir" / "images" / "ds"
|
|
for name in ["browse.ntft", "account.ntft", "room.ntft"]:
|
|
self.assertEqual((image_dir / name).stat().st_size, 2048)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|
|
|
|
|
|
class ServerFlagTests(unittest.TestCase):
|
|
def test_docs_flag_is_exact(self):
|
|
import server
|
|
old = list(sys.argv)
|
|
try:
|
|
sys.argv = ["server.py"]
|
|
self.assertFalse(server.docs_enabled_from_args())
|
|
sys.argv = ["server.py", "docs:enabled"]
|
|
self.assertTrue(server.docs_enabled_from_args())
|
|
sys.argv = ["server.py", "docs"]
|
|
self.assertFalse(server.docs_enabled_from_args())
|
|
finally:
|
|
sys.argv = old
|
|
|
|
class FakeRequest:
|
|
def __init__(self, path=b"/ds/v2-xx/index.ugo", ip="192.0.2.55", headers=None, args=None, body=b""):
|
|
import io
|
|
self.path = path
|
|
self.args = args or {}
|
|
self.content = io.BytesIO(body)
|
|
self._ip = ip
|
|
self._headers = headers or {b"host": b"flipnote.hatena.com", b"x-dsi-sid": b"test"}
|
|
self.response_code = 200
|
|
self.response_headers = {}
|
|
def getClientIP(self): return self._ip
|
|
def getAllHeaders(self): return self._headers
|
|
def setHeader(self, k, v): self.response_headers[k] = v
|
|
def setResponseCode(self, c): self.response_code = c
|
|
|
|
|
|
class RenderTests(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
install_twisted_stub()
|
|
cls.old_cwd = Path.cwd()
|
|
os.chdir(ROOT)
|
|
import hatena
|
|
cls.root = hatena.Setup()
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
os.chdir(cls.old_cwd)
|
|
|
|
def test_index_menu_renders_ugar(self):
|
|
req = FakeRequest()
|
|
data = self.root.dsResource.region.children[b"index.ugo"].render_GET(req)
|
|
self.assertTrue(data.startswith(b"UGAR"))
|
|
|
|
def test_browse_menu_renders_ugar(self):
|
|
req = FakeRequest(path=b"/ds/v2-xx/allflipnotes.ugo")
|
|
data = self.root.dsResource.region.children[b"allflipnotes.ugo"].render_GET(req)
|
|
self.assertTrue(data.startswith(b"UGAR"))
|
|
|
|
class WebRenderTests(unittest.TestCase):
|
|
@classmethod
|
|
def setUpClass(cls):
|
|
install_twisted_stub()
|
|
cls.old_cwd = Path.cwd()
|
|
os.chdir(ROOT)
|
|
import hatena
|
|
cls.root = hatena.Setup()
|
|
|
|
@classmethod
|
|
def tearDownClass(cls):
|
|
os.chdir(cls.old_cwd)
|
|
|
|
def web_request(self, path):
|
|
return FakeRequest(path=path.encode(), headers={b"host": b"localhost:8080"})
|
|
|
|
def test_home_and_browse_render(self):
|
|
for path in ["/", "/browse", "/about", "/watch/f_sample1", "/creator/r_sample1"]:
|
|
req = self.web_request(path)
|
|
data = self.root.webResource.render_GET(req)
|
|
self.assertIn(b"RexiMemo", data)
|
|
self.assertEqual(req.response_code, 200)
|
|
|
|
def test_watch_page_has_fuller_details(self):
|
|
req = self.web_request("/watch/f_sample1")
|
|
data = self.root.webResource.render_GET(req)
|
|
self.assertIn(b"First-frame preview", data)
|
|
self.assertIn(b"File size", data)
|
|
self.assertIn(b"Public ID", data)
|
|
self.assertIn(b"Comments", data)
|
|
|
|
def test_docs_are_disabled_by_default(self):
|
|
req = self.web_request("/docs")
|
|
data = self.root.webResource.render_GET(req)
|
|
self.assertEqual(req.response_code, 404)
|
|
self.assertNotIn(b"RexiMemo OSE documentation", data)
|
|
|
|
def test_docs_can_be_enabled(self):
|
|
from webapp import WebRoot
|
|
root = WebRoot(docs_enabled=True)
|
|
req = self.web_request("/docs")
|
|
data = root.render_GET(req)
|
|
self.assertEqual(req.response_code, 200)
|
|
self.assertIn(b"RexiMemo OSE documentation", data)
|
|
self.assertIn(b"docs:enabled", data)
|
|
self.assertIn(b"Behaviour", data)
|
|
self.assertIn(b"official RexiMemo DNS service", data)
|
|
self.assertIn(b"Proxy Server", data)
|
|
self.assertIn(b"8080", data)
|
|
self.assertIn(b"release-safety boundary", data)
|
|
|
|
def test_thumbnail_render(self):
|
|
req = self.web_request("/thumb/f_sample1.png")
|
|
data = self.root.webResource.render_GET(req)
|
|
self.assertTrue(data.startswith(b"\x89PNG"))
|
