Files
airdef/tools/test_hd_bench.py
T

90 lines
3.7 KiB
Python

"""Tests of tools/hd_bench.py's comparison (#82): `python3 -m unittest tools/test_hd_bench.py`."""
import argparse
import sys
import unittest
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
import hd_bench as hb # noqa: E402
def frame(w, h, v):
return bytes([v]) * (3 * w * h)
def args(**kw):
a = argparse.Namespace(budget_ms=18.0, max_flicker=1.0, max_animated=60.0, max_mean=3.0,
max_pct=5.0, max_new_animated=2.0, min_static=10.0, motion_level=hb.MOTION_LEVEL)
a.__dict__.update(kw)
return a
def judged(rgbs, base_rgbs, w=2, h=2):
rng = hb.motion_range(rgbs)
brng = hb.motion_range(base_rgbs)
entry = {"gpu_avg_ms": 1.0}
entry["flicker"] = hb.flicker_stats(rng, w, h, len(rgbs), hb.MOTION_LEVEL, hb.FLICKER_LEVEL)
entry["vs_baseline"] = hb.compare_runs(rgbs, rng, base_rgbs, brng, w, h, hb.MOTION_LEVEL)
return entry, hb.judge(entry, args())
class FlickerIsNotAnimation(unittest.TestCase):
def test_the_issues_black_white_strobe_fails(self):
# The issue: a 2x2 frame, the baseline steadily black, the run alternating black and white.
entry, reasons = judged([frame(2, 2, 0), frame(2, 2, 255)] * 2, [frame(2, 2, 0)] * 3)
self.assertEqual(entry["flicker"]["pct"], 0.0) # the old blind spot is still in these two numbers ...
self.assertEqual(entry["flicker"]["animated_pct"], 100.0)
self.assertEqual(entry["flicker"]["unsteady_pct"], 100.0)
self.assertEqual(entry["vs_baseline"]["new_animated_pct"], 100.0)
self.assertTrue(reasons, "... but the verdict is a failure")
def test_stronger_flicker_never_starts_passing(self):
w = h = 4
base = [frame(w, h, 100)] * 3
failed = []
unsteady = []
for amp in (8, 16, 32, 255):
lo, hi = 100 - min(amp // 2, 100), min(255, 100 + (amp + 1) // 2)
run = [frame(w, h, lo), frame(w, h, hi), frame(w, h, lo)]
entry, reasons = judged(run, base, w, h)
failed.append(bool(reasons))
unsteady.append(entry["flicker"]["unsteady_pct"])
self.assertEqual(failed, [True] * 4, failed)
self.assertEqual(unsteady, sorted(unsteady))
def test_a_fully_dynamic_frame_is_not_a_zero_error(self):
w = h = 2
moving = [frame(w, h, 0), frame(w, h, 255)]
entry, reasons = judged(moving, moving)
self.assertEqual(entry["vs_baseline"]["static_pct"], 0.0)
self.assertTrue(any("проверяемых" in r for r in reasons), reasons)
def test_water_and_foliage_that_also_move_in_the_baseline_pass(self):
w, h = 10, 10
n = w * h
def mixed(a, b): # the left 20% animates (water), the rest is still
f = bytearray(frame(w, h, 90))
for px in range(n // 5):
f[3 * px:3 * px + 3] = bytes([a]) * 3
return bytes(f)
run = [mixed(40, 40), mixed(120, 40), mixed(60, 40)]
base = [mixed(30, 40), mixed(130, 40), mixed(70, 40)]
entry, reasons = judged(run, base, w, h)
self.assertEqual(entry["vs_baseline"]["new_animated_pct"], 0.0)
self.assertEqual(reasons, [])
def test_the_mask_comes_from_the_baseline_not_from_the_run(self):
# Growth of the animated area against the baseline is counted and bounded.
w = h = 10
base = [frame(w, h, 90)] * 3
f = bytearray(frame(w, h, 90))
f[0:30] = bytes([250]) * 30 # 10% of the pixels
run = [bytes(f), frame(w, h, 90), bytes(f)]
entry, reasons = judged(run, base, w, h)
self.assertAlmostEqual(entry["vs_baseline"]["new_animated_pct"], 10.0)
self.assertTrue(reasons)
if __name__ == "__main__":
unittest.main()