From b1e5047a20fb6dff2e17ca66178098613eb1a7f3 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Jos=C3=A9=20Fonseca?= Date: Mon, 13 Jun 2011 10:20:05 +0100 Subject: [PATCH] Take snapshots with TRACE_SNAPSHOT. --- test.py | 164 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 114 insertions(+), 50 deletions(-) diff --git a/test.py b/test.py index ec25fab..b3d2ed9 100755 --- a/test.py +++ b/test.py @@ -27,13 +27,75 @@ '''Common test suite code.''' -import os.path +import math import optparse -import sys -import subprocess -import time +import os.path import re import signal +import subprocess +import sys +import time + +import Image +import ImageChops +import ImageEnhance + + +class Comparer: + '''Image comparer.''' + + def __init__(self, ref_image, src_image, alpha = False): + self.ref_im = Image.open(ref_image) + self.src_im = Image.open(src_image) + + # Crop to the minimum size + ref_w, ref_h = self.ref_im.size + src_w, src_h = self.src_im.size + w = min(ref_w, src_w) + h = min(ref_h, src_h) + self.ref_im = self.ref_im.crop((0, ref_h - h, w, ref_h)) + self.src_im = self.src_im.crop((0, src_h - h, w, src_h)) + + # Ignore alpha + if not alpha: + self.ref_im = self.ref_im.convert('RGB') + self.src_im = self.src_im.convert('RGB') + + self.diff = ImageChops.difference(self.src_im, self.ref_im) + + def write_diff(self, diff_image, fuzz = 0.05): + # make a difference image similar to ImageMagick's compare utility + mask = ImageEnhance.Brightness(self.diff).enhance(1.0/fuzz) + mask = mask.convert('L') + + lowlight = Image.new('RGB', self.src_im.size, (0xff, 0xff, 0xff)) + highlight = Image.new('RGB', self.src_im.size, (0xf1, 0x00, 0x1e)) + diff_im = Image.composite(highlight, lowlight, mask) + + diff_im = Image.blend(self.src_im, diff_im, 0xcc/255.0) + diff_im.save(diff_image) + + def precision(self): + # See also http://effbot.org/zone/pil-comparing-images.htm + h = self.diff.histogram() + square_error = 0 + for i in range(1, 256): + square_error += sum(h[i : 3*256: 256])*i*i + rel_error = float(square_error*2 + 1) / float(self.diff.size[0]*self.diff.size[1]*3*255*255*2) + bits = -math.log(rel_error)/math.log(2.0) + return bits + + def ae(self, chantol = 4, pixeltol = 0.03): + # Compute absolute error + # chantol = color channel tolerance + # pixeltol = ratio of pixels we allow to go completely off + + # TODO: this is approximate due to the grayscale conversion + h = self.diff.convert('L').histogram() + + ae = sum(h[int(chantol) + 1 : 256]) + + return ae <= pixeltol*self.diff.size[0]*self.diff.size[1] ansi_re = re.compile('\x1b\[[0-9]{1,2}(;[0-9]{1,2}){0,2}m') @@ -111,6 +173,10 @@ class Report: class TestCase: + standalone = False + + max_frames = 1 + def __init__(self, name, args, cwd=None, build=None, results = '.'): self.name = name self.args = args @@ -133,48 +199,51 @@ class TestCase: def run(self, report): trace = os.path.abspath(os.path.join(self.results, self.name + '.trace')) + ref_prefix = os.path.abspath(os.path.join(self.results, self.name + '.ref.')) + src_prefix = os.path.join(self.results, self.name + '.src.') + diff_prefix = os.path.join(self.results, self.name + '.diff.') ld_preload = self._get_build_path('glxtrace.so') env = os.environ.copy() env['LD_PRELOAD'] = ld_preload env['TRACE_FILE'] = trace + env['TRACE_SNAPSHOT'] = ref_prefix + env['TRACE_FRAMES'] = str(self.max_frames) - window_name = self.args[0] - - p = popen(self.args, cwd=self.cwd) - for i in range(3): - time.sleep(1) - if p.poll() is not None: - break - if subprocess.call(['xwininfo', '-name', window_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0: - break - if p.returncode is None: - p.terminate() - elif p.returncode: - sys.stdout.write('SKIP (app)\n') - return + if self.standalone: + p = popen(self.args, cwd=self.cwd) + for i in range(3): + time.sleep(1) + if p.poll() is not None: + break + if p.returncode is None: + p.terminate() + elif p.returncode: + sys.stdout.write('SKIP (app)\n') + return - ref_image = os.path.join(self.results, self.name + '.ref.png') p = popen(self.args, env=env, cwd=self.cwd) try: for i in range(5): time.sleep(1) if p.poll() is not None: break - if subprocess.call(['xwininfo', '-name', window_name], stdout=subprocess.PIPE, stderr=subprocess.PIPE) == 0: - break - - if p.returncode is None: - subprocess.call("xwd -name '%s' | xwdtopnm | pnmtopng > '%s'" % (window_name, ref_image), shell=True) finally: if p.returncode is None: p.terminate() p.wait() elif p.returncode: - sys.stdout.write('FAIL (trace)\n') + if self.standalone: + sys.stdout.write('FAIL (trace)\n') + else: + sys.stdout.write('SKIP (app)\n') return + if not os.path.isfile(trace): + sys.stdout.write('SKIP (no trace)\n') + return + p = popen([self._get_build_path('tracedump'), trace], stdout=subprocess.PIPE) call_re = re.compile('^([0-9]+) (\w+)\(') swapbuffers = 0 @@ -204,44 +273,39 @@ class TestCase: else: args += ['-sb'] frames = flushes - if os.path.exists(ref_image) and frames < 10: - snapshot_prefix = os.path.join(self.results, self.name + '.') - args += ['-s', snapshot_prefix] - else: - snapshot_prefix = None + args += ['-s', src_prefix] args += [trace] p = popen(args, stdout=subprocess.PIPE) image_re = re.compile('^Wrote (.*\.png)$') - image = None + images = [] for line in p.stdout: line = line.rstrip() mo = image_re.match(line) if mo: image = mo.group(1) + if image.startswith(src_prefix): + image = image[len(src_prefix):] + images.append(image) p.wait() if p.returncode != 0: sys.stdout.write('FAIL (glretrace)\n') return - if image: - delta_image = os.path.join(self.results, self.name + '.diff.png') - p = popen([ - 'compare', - '-alpha', 'opaque', - '-metric', 'AE', - '-fuzz', '5%', - '-dissimilarity-threshold', '1', - ref_image, image, delta_image - ], stderr = subprocess.PIPE) - _, stderr = p.communicate() - - try: - ae = int(stderr) - except ValueError: - ae = 9999 - - if ae: - report.add_snapshot(ref_image, image, delta_image) + for image in images: + ref_image = ref_prefix + image + src_image = src_prefix + image + diff_image = diff_prefix + image + + if not os.path.isfile(ref_image): + continue + assert os.path.isfile(src_image) + + comparer = Comparer(ref_image, src_image) + match = comparer.ae() + sys.stdout.write('%s: %s bits\n' % (image, comparer.precision())) + if not match: + comparer.write_diff(diff_image) + report.add_snapshot(ref_image, src_image, diff_image) sys.stdout.write('FAIL (snapshot)\n') return -- 2.43.0