"""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()