2023-06-17 03:13:40 +00:00
|
|
|
"""
|
|
|
|
surplus test runner
|
|
|
|
-------------------
|
2023-09-04 14:37:09 +00:00
|
|
|
by mark <mark@joshwel.co>
|
2023-06-17 03:13:40 +00:00
|
|
|
|
|
|
|
This is free and unencumbered software released into the public domain.
|
|
|
|
|
|
|
|
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
|
|
distribute this software, either in source code form or as a compiled
|
|
|
|
binary, for any purpose, commercial or non-commercial, and by any
|
|
|
|
means.
|
|
|
|
|
|
|
|
In jurisdictions that recognize copyright laws, the author or authors
|
|
|
|
of this software dedicate any and all copyright interest in the
|
|
|
|
software to the public domain. We make this dedication for the benefit
|
|
|
|
of the public at large and to the detriment of our heirs and
|
|
|
|
successors. We intend this dedication to be an overt act of
|
|
|
|
relinquishment in perpetuity of all present and future rights to this
|
|
|
|
software under copyright law.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
|
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
|
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
|
|
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
|
|
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
|
|
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
|
|
OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
|
|
|
|
For more information, please refer to <http://unlicense.org/>
|
|
|
|
"""
|
|
|
|
|
2023-09-02 10:08:49 +00:00
|
|
|
from io import StringIO
|
2023-06-17 03:13:40 +00:00
|
|
|
from sys import stderr
|
|
|
|
from textwrap import indent
|
|
|
|
from traceback import format_exception
|
|
|
|
from typing import Final, NamedTuple
|
|
|
|
|
|
|
|
import surplus
|
|
|
|
|
|
|
|
INDENT: Final[int] = 3
|
2023-09-02 09:35:33 +00:00
|
|
|
MINIMUM_PASS_RATE: Final[float] = 0.7 # because results can be flaky
|
2023-06-17 03:13:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
class ContinuityTest(NamedTuple):
|
|
|
|
query: str
|
2023-09-02 10:00:54 +00:00
|
|
|
expected: list[str]
|
2023-06-17 03:13:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
class TestFailure(NamedTuple):
|
|
|
|
test: ContinuityTest
|
|
|
|
exception: Exception
|
|
|
|
output: str
|
2023-09-02 10:08:49 +00:00
|
|
|
stderr: StringIO
|
2023-06-17 03:13:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
tests: list[ContinuityTest] = [
|
|
|
|
ContinuityTest(
|
2023-09-02 09:35:33 +00:00
|
|
|
query="8R3M+F8 Singapore",
|
2023-10-14 20:06:30 +00:00
|
|
|
expected=[("Wisma Atria\n" "435 Orchard Road\n" "238877\n" "Central, Singapore")],
|
2023-06-17 03:13:40 +00:00
|
|
|
),
|
|
|
|
ContinuityTest(
|
|
|
|
query="9R3J+R9 Singapore",
|
2023-09-02 10:00:54 +00:00
|
|
|
expected=[
|
|
|
|
(
|
|
|
|
"Thomson Plaza\n"
|
|
|
|
"301 Upper Thomson Road\n"
|
|
|
|
"Sin Ming, Bishan\n"
|
|
|
|
"574408\n"
|
|
|
|
"Central, Singapore"
|
|
|
|
)
|
|
|
|
],
|
2023-06-17 03:13:40 +00:00
|
|
|
),
|
|
|
|
ContinuityTest(
|
|
|
|
query="3RQ3+HW3 Pemping, Batam City, Riau Islands, Indonesia",
|
2023-09-02 10:00:54 +00:00
|
|
|
expected=[
|
|
|
|
("Batam\n" "Kepulauan Riau, Indonesia"),
|
|
|
|
("Batam\n" "Sumatera, Kepulauan Riau, Indonesia"),
|
|
|
|
],
|
2023-06-17 03:13:40 +00:00
|
|
|
),
|
2023-06-17 03:18:54 +00:00
|
|
|
ContinuityTest(
|
2023-09-02 09:35:33 +00:00
|
|
|
query="St Lucia, Queensland, Australia G227+XF",
|
2023-09-02 10:00:54 +00:00
|
|
|
expected=[
|
|
|
|
(
|
|
|
|
"The University of Queensland\n"
|
|
|
|
"Macquarie Street\n"
|
|
|
|
"St Lucia, Greater Brisbane\n"
|
|
|
|
"4072\n"
|
|
|
|
"Queensland, Australia"
|
|
|
|
),
|
|
|
|
(
|
|
|
|
"The University of Queensland\n"
|
2023-09-02 10:57:26 +00:00
|
|
|
"Eleanor Schonell Bridge\n"
|
2023-09-02 10:00:54 +00:00
|
|
|
"St Lucia, Greater Brisbane, Dutton Park\n"
|
|
|
|
"4072\n"
|
|
|
|
"Queensland, Australia"
|
2023-09-02 10:08:49 +00:00
|
|
|
),
|
2023-10-14 20:06:30 +00:00
|
|
|
(
|
|
|
|
"The University of Queensland\n"
|
|
|
|
"Hawken Drive\n"
|
|
|
|
"St Lucia, Greater Brisbane\n"
|
|
|
|
"4072\n"
|
|
|
|
"Queensland, Australia"
|
|
|
|
),
|
2023-09-02 10:00:54 +00:00
|
|
|
],
|
2023-09-02 09:35:33 +00:00
|
|
|
),
|
|
|
|
ContinuityTest(
|
|
|
|
query="Ngee Ann Polytechnic, Singapore",
|
2023-09-05 17:34:28 +00:00
|
|
|
expected=[
|
|
|
|
(
|
|
|
|
"Ngee Ann Polytechnic\n"
|
|
|
|
"535 Clementi Road\n"
|
|
|
|
"Bukit Timah\n"
|
|
|
|
"599489\n"
|
|
|
|
"Northwest, Singapore"
|
2023-10-14 20:06:30 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
"Ngee Ann Polytechnic\n"
|
|
|
|
"535 Clementi Road\n"
|
|
|
|
"Ewart Park, Bukit Timah\n"
|
|
|
|
"599489\n"
|
|
|
|
"Northwest, Singapore"
|
|
|
|
),
|
2023-09-05 17:34:28 +00:00
|
|
|
],
|
2023-09-02 09:35:33 +00:00
|
|
|
),
|
|
|
|
ContinuityTest(
|
|
|
|
query="1.3521, 103.8198",
|
2023-09-05 17:34:28 +00:00
|
|
|
expected=[
|
|
|
|
(
|
|
|
|
"MacRitchie Nature Trail\n"
|
|
|
|
"Central Water Catchment\n"
|
|
|
|
"574325\n"
|
|
|
|
"Central, Singapore"
|
|
|
|
)
|
|
|
|
],
|
2023-06-17 03:18:54 +00:00
|
|
|
),
|
2023-09-06 17:53:35 +00:00
|
|
|
ContinuityTest(
|
|
|
|
query="8WWJ+4P, Singapore", # a comma!
|
|
|
|
expected=[
|
|
|
|
(
|
|
|
|
"Temasek Polytechnic\n"
|
|
|
|
"21 Tampines Avenue 1\n"
|
|
|
|
"Tampines West\n"
|
|
|
|
"529757\n"
|
|
|
|
"Northeast, Singapore"
|
2023-09-19 15:06:56 +00:00
|
|
|
),
|
|
|
|
(
|
|
|
|
"Temasek Polytechnic\n"
|
|
|
|
"21 Tampines Avenue 1\n"
|
|
|
|
"529757\n"
|
|
|
|
"Southeast, Singapore"
|
|
|
|
),
|
2023-09-06 17:53:35 +00:00
|
|
|
],
|
|
|
|
),
|
2023-10-14 20:06:30 +00:00
|
|
|
ContinuityTest(
|
|
|
|
query="J286+WV San Cesario sul Panaro, Modena, Italy",
|
|
|
|
expected=[
|
|
|
|
(
|
|
|
|
"Via Emilia 1193a\n"
|
|
|
|
"Unione dei comuni del Sorbara, Sant'Anna\n"
|
|
|
|
"41018 Modena Emilia-Romagna\n"
|
|
|
|
"Italia"
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
|
|
|
ContinuityTest(
|
|
|
|
query="GQ2G+GX Johor Bahru, Johor, Malaysia",
|
|
|
|
expected=[
|
|
|
|
(
|
|
|
|
"The Mall, Mid Valley Southkey\n"
|
|
|
|
"Jalan Bakar Batu\n"
|
|
|
|
"81100 Taman Sentosa Johor Bahru\n"
|
|
|
|
"Iskandar Malaysia, Johor, Malaysia"
|
|
|
|
),
|
|
|
|
],
|
|
|
|
),
|
2023-06-17 03:13:40 +00:00
|
|
|
]
|
|
|
|
|
|
|
|
|
|
|
|
class SurplusFailure(Exception):
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
class QueryParseFailure(Exception):
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
class ContinuityFailure(Exception):
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
|
|
def main() -> int:
|
|
|
|
failures: list[TestFailure] = []
|
|
|
|
|
|
|
|
for idx, test in enumerate(tests, start=1):
|
|
|
|
print(f"[{idx}/{len(tests)}] {test.query}")
|
2023-09-02 09:35:33 +00:00
|
|
|
|
2023-09-02 10:00:54 +00:00
|
|
|
test_stderr = StringIO()
|
|
|
|
|
2023-06-17 03:13:40 +00:00
|
|
|
output: str = ""
|
2023-09-02 10:57:26 +00:00
|
|
|
behaviour = surplus.Behaviour(test.query, stderr=test_stderr, debug=True)
|
2023-06-17 03:13:40 +00:00
|
|
|
|
|
|
|
try:
|
2023-09-02 09:35:33 +00:00
|
|
|
query = surplus.parse_query(behaviour)
|
2023-06-17 03:13:40 +00:00
|
|
|
|
2023-09-02 09:35:33 +00:00
|
|
|
if not query:
|
|
|
|
raise QueryParseFailure(query.cry())
|
2023-06-17 03:13:40 +00:00
|
|
|
|
2023-09-02 09:35:33 +00:00
|
|
|
result = surplus.surplus(query.get(), behaviour)
|
2023-06-17 03:13:40 +00:00
|
|
|
|
2023-09-02 09:35:33 +00:00
|
|
|
if not result:
|
|
|
|
raise SurplusFailure(result.cry())
|
2023-06-17 03:13:40 +00:00
|
|
|
|
2023-09-02 09:35:33 +00:00
|
|
|
output = result.get()
|
2023-06-17 03:13:40 +00:00
|
|
|
|
2023-09-02 10:00:54 +00:00
|
|
|
if output not in test.expected:
|
|
|
|
raise ContinuityFailure("did not match any expected outputs")
|
2023-06-17 03:13:40 +00:00
|
|
|
|
|
|
|
except Exception as exc:
|
2023-09-02 10:08:49 +00:00
|
|
|
failures.append(
|
|
|
|
TestFailure(test=test, exception=exc, output=output, stderr=test_stderr)
|
|
|
|
)
|
2023-09-02 09:35:33 +00:00
|
|
|
stderr.write(indent(text="(fail)", prefix=INDENT * " ") + "\n\n")
|
2023-06-17 03:13:40 +00:00
|
|
|
|
|
|
|
else:
|
2023-06-17 03:27:50 +00:00
|
|
|
stderr.write(indent(text="(pass)", prefix=INDENT * " ") + "\n\n")
|
2023-06-17 03:13:40 +00:00
|
|
|
|
2023-06-17 03:27:50 +00:00
|
|
|
if len(failures) > 0:
|
|
|
|
print(f"\n--- failures ---\n")
|
2023-06-17 03:13:40 +00:00
|
|
|
|
|
|
|
for fail in failures:
|
|
|
|
print(
|
2023-06-20 20:53:02 +00:00
|
|
|
f"[{tests.index(fail.test) + 1}/{len(tests)}] {fail.test.query}\n"
|
2023-06-17 03:18:54 +00:00
|
|
|
+ (
|
|
|
|
indent("\n".join(format_exception(fail.exception)), prefix=INDENT * " ")
|
|
|
|
+ "\n"
|
|
|
|
)
|
2023-09-02 10:17:05 +00:00
|
|
|
+ (indent(text="Expected:", prefix=INDENT * " "))
|
|
|
|
)
|
|
|
|
|
|
|
|
for expected_output in fail.test.expected:
|
|
|
|
print(
|
2023-09-02 10:57:26 +00:00
|
|
|
indent(text=repr(expected_output), prefix=(2 * INDENT) * " ")
|
|
|
|
+ "\n"
|
2023-09-02 10:17:05 +00:00
|
|
|
+ (indent(text=expected_output, prefix=(2 * INDENT) * " ") + "\n")
|
|
|
|
)
|
|
|
|
|
|
|
|
print(
|
2023-09-02 10:57:26 +00:00
|
|
|
indent(text="Actual:", prefix=INDENT * " ")
|
|
|
|
+ "\n"
|
2023-06-17 03:13:40 +00:00
|
|
|
+ (indent(text=repr(fail.output), prefix=(2 * INDENT) * " ") + "\n")
|
2023-09-02 10:00:54 +00:00
|
|
|
+ (indent(text=fail.output, prefix=(2 * INDENT) * " ") + "\n\n")
|
|
|
|
+ (indent(text="stderr:", prefix=INDENT * " ") + "\n")
|
2023-09-02 10:08:49 +00:00
|
|
|
+ (indent(text=fail.stderr.getvalue(), prefix=(2 * INDENT) * " "))
|
2023-06-17 03:13:40 +00:00
|
|
|
)
|
|
|
|
|
2023-09-02 09:35:33 +00:00
|
|
|
passes = len(tests) - len(failures)
|
2023-09-02 10:00:54 +00:00
|
|
|
pass_rate = passes / len(tests)
|
2023-09-02 09:35:33 +00:00
|
|
|
|
|
|
|
print(
|
|
|
|
f"complete: {passes} passed, {len(failures)} failed "
|
2023-09-02 10:00:54 +00:00
|
|
|
f"({pass_rate * 100:.0f}%/{MINIMUM_PASS_RATE * 100:.0f}%)"
|
2023-09-02 09:35:33 +00:00
|
|
|
)
|
|
|
|
|
2023-09-02 10:00:54 +00:00
|
|
|
if pass_rate < MINIMUM_PASS_RATE:
|
2023-09-02 09:35:33 +00:00
|
|
|
print("continuity pass rate is under minimum, test suite failed ;<")
|
|
|
|
return 1
|
2023-06-17 03:27:50 +00:00
|
|
|
|
2023-09-02 09:35:33 +00:00
|
|
|
print("continuity tests passed :>")
|
|
|
|
return 0
|
2023-06-17 03:13:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
exit(main())
|