def parse_liquid_tests(lines):
import re
from collections import defaultdict
TEST_RE = re.compile(r"^\s*\d+\[\s*\d+\.\d+ ms\]\s+(\w+)\s+passed\s+\d+/\s*\d+\s+checks\s+\(\s*\d+\.\d+%\)\s+(\w+)")
MODULE_RE = re.compile(r"^(\d+): (\w+):$")
module_map = defaultdict(list)
passing_tests = []
failing_tests = []
current_module = None
for line in lines:
if m := TEST_RE.match(line):
test_name = m.group(2)
module_map[current_module].append(test_name)
if m.group(1) == "PASS":
passing_tests.append(test_name)
else:
failing_tests.append(test_name)
if m := MODULE_RE.match(line):
current_module = m.group(2)
print(len(module_map), len(passing_tests), len(failing_tests))
return module_map, passing_tests, failing_tests
def parse_yagi_tests(lines):
import re
RUNNING_TEST_RE = re.compile(r"^running (\d+) tests$")
TEST_RE = re.compile(r"^\s*test (\S+) \.\.\. (ok|FAILED)$")
TEST_ANNOTATION_RE = re.compile(r"^\s*!! liquid test annotation: autotest_(\S+) -> (\S+) !!$")
test_map = {}
test_count = None
passing_tests = []
failing_tests = []
for line in lines:
if m := RUNNING_TEST_RE.match(line):
test_count = int(m.group(1))
if test_count:
if m := TEST_RE.match(line):
test_name = m.group(1).split("::")[-1]
test_result = m.group(2)
if test_result == "ok":
passing_tests.append(test_name)
else:
failing_tests.append(test_name)
test_count -= 1
if m := TEST_ANNOTATION_RE.match(line):
liquid_test_name = m.group(1)
yagi_test_name = m.group(2)
if yagi_test_name in test_map:
print(f"Duplicate test name: {yagi_test_name}")
test_map[yagi_test_name] = liquid_test_name
liquid_passing = [test_map[test] for test in passing_tests if test in test_map]
liquid_failing = [test_map[test] for test in failing_tests if test in test_map]
return liquid_passing, liquid_failing
def main():
import os
with open("liquid-test.out", "r") as f:
liquid_module_map, liquid_passing, liquid_failing = parse_liquid_tests(f.readlines())
with open("yagi-test.out", "r") as f:
yagi_passing, yagi_failing = parse_yagi_tests(f.readlines())
all_liquid_pass = 0
all_liquid_fail = 0
all_liquid_missing = 0
all_yagi_pass = 0
all_yagi_fail = 0
all_yagi_missing = 0
for module, tests in liquid_module_map.items():
liquid_pass = 0
liquid_fail = 0
liquid_missing = 0
yagi_pass = 0
yagi_fail = 0
yagi_missing = 0
for test in tests:
if test in liquid_passing:
liquid_pass += 1
elif test in liquid_failing:
liquid_fail += 1
else:
liquid_missing += 1
if test in yagi_passing:
yagi_pass += 1
elif test in yagi_failing:
yagi_fail += 1
else:
yagi_missing += 1
all_liquid_pass += liquid_pass
all_liquid_fail += liquid_fail
all_liquid_missing += liquid_missing
all_yagi_pass += yagi_pass
all_yagi_fail += yagi_fail
all_yagi_missing += yagi_missing
yagi_pass_pct = yagi_pass / (liquid_pass + liquid_fail) * 100
yagi_present_pct = (yagi_pass + yagi_fail) / (liquid_pass + liquid_fail) * 100
print(f"{module:30s}: {liquid_pass:4d} {liquid_fail:4d} {liquid_missing:4d} {yagi_pass:4d} {yagi_fail:4d} {yagi_missing:4d} {yagi_pass_pct:8.2f}% {yagi_present_pct:8.2f}%")
all_yagi_pass_pct = all_yagi_pass / (all_liquid_pass + all_liquid_fail) * 100
all_yagi_present_pct = (all_yagi_pass + all_yagi_fail) / (all_liquid_pass + all_liquid_fail) * 100
total = "TOTAL"
print(f"\n{total:30s}: {all_liquid_pass:4d} {all_liquid_fail:4d} {all_liquid_missing:4d} {all_yagi_pass:4d} {all_yagi_fail:4d} {all_yagi_missing:4d} {all_yagi_pass_pct:8.2f}% {all_yagi_present_pct:8.2f}%")
with open("LIQUID_COMPAT.md", "w") as f:
for module, tests in liquid_module_map.items():
f.write(f"\n\n## {module}\n")
f.write(f"| Test | Liquid | Yagi |\n")
f.write(f"| ---- | ------ | ---- |\n")
for test in tests:
f.write(f"| {test:40s} |")
if test in liquid_passing:
f.write(f" ✅")
else:
f.write(f" ❌")
f.write(f" |")
if test in yagi_passing:
f.write(f" ✅")
elif test in yagi_failing:
f.write(f" ❌")
else:
f.write(f" ❓")
f.write(f" |\n")
if __name__ == "__main__":
main()