import os import os.path import mgba.core import mgba.image import cinema.movie import itertools import glob import re import yaml from copy import deepcopy from cinema import VideoFrame from cinema.util import dict_merge class CinemaTest(object): TEST = 'test.(mvl|gb|gba|nds)' def __init__(self, path, root, settings={}): self.full_path = path or [] self.path = os.path.abspath(os.path.join(root, *self.full_path)) self.root = root self.name = '.'.join(path) self.settings = settings try: with open(os.path.join(self.path, 'manifest.yml'), 'r') as f: dict_merge(self.settings, yaml.safe_load(f)) except IOError: pass self.tests = {} def __repr__(self): return '<%s %s>' % (self.__class__.__name__, self.name) def setup(self): results = [f for f in glob.glob(os.path.join(self.path, 'test.*')) if re.search(self.TEST, f)] self.core = mgba.core.load_path(results[0]) if 'config' in self.settings: self.config = mgba.core.Config(defaults=self.settings['config']) self.core.load_config(self.config) self.core.reset() def add_test(self, name, cls=None, settings={}): cls = cls or self.__class__ new_settings = deepcopy(self.settings) dict_merge(new_settings, settings) self.tests[name] = cls(self.full_path + [name], self.root, new_settings) return self.tests[name] def output_settings(self): output_settings = {} if 'frames' in self.settings: output_settings['limit'] = self.settings['frames'] if 'skip' in self.settings: output_settings['skip'] = self.settings['skip'] return output_settings def __lt__(self, other): return self.path < other.path class VideoTest(CinemaTest): BASELINE = 'baseline_%04u.png' def setup(self): super(VideoTest, self).setup() self.tracer = cinema.movie.Tracer(self.core) def generate_frames(self): for i, frame in zip(itertools.count(), self.tracer.video(**self.output_settings())): try: baseline = VideoFrame.load(os.path.join(self.path, self.BASELINE % i)) yield baseline, frame, VideoFrame.diff(baseline, frame) except IOError: yield None, frame, (None, None) def test(self): self.baseline, self.frames, self.diffs = zip(*self.generate_frames()) assert not any(any(diffs[0].image.convert("L").point(bool).getdata()) for diffs in self.diffs) def generate_baseline(self): for i, frame in zip(itertools.count(), self.tracer.video(**self.output_settings())): frame.save(os.path.join(self.path, self.BASELINE % i)) def gather_tests(root=os.getcwd()): tests = CinemaTest([], root) for path, _, files in os.walk(root): test = [f for f in files if re.match(CinemaTest.TEST, f)] if not test: continue prefix = os.path.commonprefix([path, root]) suffix = path[len(prefix)+1:] test_path = suffix.split(os.sep) test_root = tests for component in test_path[:-1]: new_test = test_root.tests.get(component) if not new_test: new_test = test_root.add_test(component) test_root = new_test test_root.add_test(test_path[-1], VideoTest) return tests