summaryrefslogtreecommitdiffstats
path: root/debian/jstest/jstest.py
diff options
context:
space:
mode:
Diffstat (limited to 'debian/jstest/jstest.py')
-rw-r--r--debian/jstest/jstest.py153
1 files changed, 153 insertions, 0 deletions
diff --git a/debian/jstest/jstest.py b/debian/jstest/jstest.py
new file mode 100644
index 0000000..d1fbd59
--- /dev/null
+++ b/debian/jstest/jstest.py
@@ -0,0 +1,153 @@
+#!/usr/bin/python3
+# encoding=UTF-8
+
+# Copyright © 2011 Jakub Wilk <jwilk@debian.org>
+# © 2013-2022 Dmitry Shachnev <mitya57@debian.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import urllib.parse
+import urllib.request
+import re
+import unittest
+import gi
+
+gi.require_version('Gtk', '4.0')
+gi.require_version('WebKit', '6.0')
+from gi.repository import GLib, Gtk, WebKit
+
+default_time_limit = 40.0
+
+# HTTP browser
+# ============
+
+class Timeout(Exception):
+ pass
+
+class Browser(object):
+
+ def __init__(self, options):
+ settings = WebKit.Settings()
+ settings.set_property('allow-file-access-from-file-urls', True)
+ settings.set_property('enable-write-console-messages-to-stdout', True)
+ self._time_limit = 0
+ self._view = WebKit.WebView(settings=settings)
+ self._view.connect('notify::title', self._on_title_changed)
+ self._result = None
+ self._id = 0
+ self._application = Gtk.Application()
+ self._application.set_application_id('org.debian.sphinx.jstest')
+ self._application.connect('activate', self._activate)
+
+ def _activate(self, application):
+ self._window = Gtk.ApplicationWindow(application=application)
+ self._window.set_child(self._view)
+ self._window.show()
+
+ def _on_title_changed(self, webview, user_data):
+ contents = webview.get_property('title')
+ webview.evaluate_javascript('document.title = ""', -1)
+ found = re.match(r"(?P<n_results>\d+) (?P<n_links>\d+) (?P<n_highlights>\d+)", contents)
+ if found:
+ self._result = found.groupdict()
+ self._window.destroy()
+ GLib.source_remove(self._id)
+ self._id = 0
+
+ def _quit(self):
+ self._view.evaluate_javascript(
+ "var n_results = $('#search-results > p:first').text().match(/found (\d+) page/)[1];\n"
+ "var n_links = $('#search-results a').length;\n"
+ "var n_highlights = $('#search-results .highlighted').length;\n"
+ "document.title = `${n_results} ${n_links} ${n_highlights}`;",
+ -1,
+ )
+ if self._time_limit < 0:
+ self._result = None
+ self._window.destroy()
+ return GLib.SOURCE_REMOVE
+
+ self._time_limit -= 1
+ return GLib.SOURCE_CONTINUE
+
+ def wget(self, url, time_limit=default_time_limit):
+ self._view.load_uri(url)
+ self._time_limit = time_limit
+ self._id = GLib.timeout_add_seconds(1, self._quit)
+ self._application.run()
+ if self._result is None:
+ raise Timeout
+ return self._result
+
+
+# Actual tests
+# ============
+
+def test_html(result, options):
+
+ class TestCase(unittest.TestCase):
+
+ if options.n_results is not None:
+ def test_n_results(self):
+ n_results = int(result['n_results'])
+ self.assertEqual(n_results, options.n_results)
+
+ if options.n_links is not None:
+ def test_n_links(self):
+ n_links = int(result['n_links'])
+ self.assertEqual(n_links, options.n_links)
+
+ if options.n_highlights is not None:
+ def test_n_highlights(self):
+ n_highlights = int(result['n_highlights'])
+ self.assertEqual(n_highlights, options.n_highlights)
+
+ TestCase.__name__ = 'TestCase(%r)' % options.search_term
+
+ suite = unittest.TestLoader().loadTestsFromTestCase(TestCase)
+ return unittest.TextTestRunner(verbosity=2).run(suite)
+
+def test_directory(directory, options, time_limit=default_time_limit):
+ url = urllib.parse.urljoin('file:', urllib.request.pathname2url(directory))
+ url = urllib.parse.urljoin(url, 'html/search.html?q=' + urllib.parse.quote_plus(options.search_term))
+ browser = Browser(options)
+ result = browser.wget(url, time_limit)
+ return test_html(result, options)
+
+def main():
+ import argparse
+ parser = argparse.ArgumentParser()
+ parser.add_argument('--time-limit', type=float, default=default_time_limit)
+ parser.add_argument('directory', metavar='DIRECTORY')
+ parser.add_argument('search_term', metavar='SEARCH-TERM')
+ parser.add_argument('--n-results', type=int)
+ parser.add_argument('--n-links', type=int)
+ parser.add_argument('--n-highlights', type=int)
+ options = parser.parse_args()
+ test_directory(options.directory, options=options, time_limit=options.time_limit)
+
+if __name__ == '__main__':
+ main()
+
+# vim:ts=4 sw=4 et