about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNguyễn Gia Phong <cnx@loang.net>2025-05-25 19:05:44 +0900
committerNguyễn Gia Phong <cnx@loang.net>2025-05-25 19:05:44 +0900
commit7c888edbb9512e8cc75c302d487b5c2e4eace62c (patch)
tree07deb8a957be8aa26d2b45a489e43086ed071f78
parent552c60f5fd0395acabfd8320a5372c54df23a5ea (diff)
downloadscadere-7c888edbb9512e8cc75c302d487b5c2e4eace62c.tar.gz
Add some basic tests
-rw-r--r--.gitignore3
-rw-r--r--README.md15
-rw-r--r--pyproject.toml13
-rw-r--r--tst/test_listen.py48
4 files changed, 79 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 1be5bdb..cc74c32 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
+.coverage
+.hypothesis/
+.pytest_cache/
 __pycache__/
 dist/
diff --git a/README.md b/README.md
index c7d67e8..9fa6de9 100644
--- a/README.md
+++ b/README.md
@@ -36,8 +36,20 @@ Options:
   -h, --help  show this help message and exit
 ```
 
+## Hacking
+
+Unit testing is done with [Hypothesis] and [pytest].  Since scadere
+does not depend on any Python package, testing can be safely done in-tree:
+
+    PYTHONPATH=src pytest
+
 ## Contributing
 
+Please make sure that patches maintain the full branch [coverage]:
+
+    PYTHONPATH=src coverage run
+    coverage report
+
 Patches should be sent to [chung@loa.loang.net][loang mailing list]
 using [`git send-email`][git send-email], with the following configuration:
 
@@ -53,6 +65,9 @@ under the terms of the GNU [Affero General Public License][agplv3] as
 published by the Free Software Foundation, either version 3 of the License,
 or (at your option) any later version.
 
+[Hypothesis]: https://hypothesis.rtfd.io
+[pytest]: https://docs.pytest.org
+[coverage]: https://coverage.rtfd.io
 [loang mailing list]: https://loa.loang.net/chung
 [git send-email]: https://git-send-email.io
 [agplv3]: https://www.gnu.org/licenses/agpl-3.0.html
diff --git a/pyproject.toml b/pyproject.toml
index 91b3428..4104f67 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -23,3 +23,16 @@ classifiers = [
 dynamic = [ 'version' ]
 urls = { Source = 'https://trong.loang.net/scadere' }
 scripts = { scadere = 'scadere.__main__:main' }
+
+[tool.pytest.ini_options]
+testpaths = [ 'tst' ]
+
+[tool.coverage.run]
+branch = true
+command_line = '-m pytest'
+source = [ '.' ]
+
+[tool.coverage.report]
+fail_under = 100
+show_missing = true
+skip_covered = true
diff --git a/tst/test_listen.py b/tst/test_listen.py
new file mode 100644
index 0000000..d3a8052
--- /dev/null
+++ b/tst/test_listen.py
@@ -0,0 +1,48 @@
+# Tests for the HTTP server
+# Copyright (C) 2025  Nguyễn Gia Phong
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License as published
+# by the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Affero General Public License for more details.
+#
+# You should have received a copy of the GNU Affero General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+from base64 import urlsafe_b64decode as from_base64
+
+from hypothesis import given
+from hypothesis.strategies import integers, datetimes, text
+from hypothesis.provisional import domains
+
+from scadere.listen import body, path
+
+
+@given(domains(), integers(1, 65535), text(), integers(0, 256**20))
+def test_path(hostname, port, issuer, serial):
+    r = path(hostname, port, issuer, hex(serial).removeprefix('0x')).split('/')
+    assert(r[0] == hostname)
+    assert(int(r[1]) == port)
+    assert(from_base64(r[2]).decode() == issuer)
+    assert(int(r[3], 16) == serial)
+
+
+@given(domains(), integers(1, 65535), text(), integers(0, 256**20),
+       datetimes(), datetimes())
+def test_body(hostname, port, issuer, serial, not_before, not_after):
+    r = body(not_before, not_after, hostname, port,
+             hex(serial).removeprefix('0x'), issuer)
+    assert(r[-1][0] == 'dl')
+    d = dict(zip((v for k, v in r[-1][1:] if k == 'dt'),
+                 (v for k, v in r[-1][1:] if k == 'dd')))
+    assert(d['Domain'] == hostname)
+    assert(d['Port'] == port)
+    assert(d['Issuer'] == issuer)
+    assert(int(d['Serial number'], 16) == serial)
+    assert(d['Valid from'] == not_before)
+    assert(d['Valid until'] == not_after)