示例#1
0
    def assert_equal(self):
        __tracebackhide__ = True
        self.end()
        self.different_pixels = 0
        actual_image: QImage = self.actual.device().toImage()
        expected_image: QImage = self.expected.device().toImage()
        diff_pixmap = QPixmap(actual_image.width(), actual_image.height())
        diff = QPainter(diff_pixmap)
        try:
            white = QColor('white')
            diff.fillRect(0, 0, actual_image.width(), actual_image.height(),
                          white)
            for x in range(actual_image.width()):
                for y in range(actual_image.height()):
                    actual_colour = actual_image.pixelColor(x, y)
                    expected_colour = expected_image.pixelColor(x, y)
                    diff.setPen(
                        self.diff_colour(actual_colour, expected_colour, x, y))
                    diff.drawPoint(x, y)
        finally:
            diff.end()
        diff_image: QImage = diff.device().toImage()

        display_diff(actual_image, diff_image, expected_image,
                     self.different_pixels)

        if self.different_pixels == 0:
            return
        actual_image.save(str(self.work_dir / (self.name + '_actual.png')))
        expected_image.save(str(self.work_dir / (self.name + '_expected.png')))
        diff_path = self.work_dir / (self.name + '_diff.png')
        is_saved = diff_image.save(str(diff_path))
        diff_width = self.diff_max_x - self.diff_min_x + 1
        diff_height = self.diff_max_y - self.diff_min_y + 1
        diff_section = QImage(diff_width, diff_height, QImage.Format_RGB32)
        diff_section_painter = QPainter(diff_section)
        try:
            diff_section_painter.drawPixmap(0, 0, diff_width, diff_height,
                                            QPixmap.fromImage(diff_image),
                                            self.diff_min_x, self.diff_min_y,
                                            diff_width, diff_height)
        finally:
            diff_section_painter.end()
        # To see an image dumped in the Travis CI log, copy the text from the
        # log, and paste it in test_pixmap_differ.test_decode_image.
        print(f'Encoded image of differing section '
              f'({self.diff_min_x}, {self.diff_min_y}) - '
              f'({self.diff_max_x}, {self.diff_max_y}):')
        print(encode_image(diff_section))
        message = f'Found {self.different_pixels} different pixels, '
        message += f'see' if is_saved else 'could not write'
        message += f' {diff_path.relative_to(Path(__file__).parent.parent)}.'
        assert self.different_pixels == 0, message
示例#2
0
    def assert_equal(self):
        __tracebackhide__ = True
        self.end()
        self.different_pixels = 0
        actual_image: QImage = self.actual.device().toImage()
        expected_image: QImage = self.expected.device().toImage()
        diff_pixmap = QPixmap(actual_image.width(), actual_image.height())
        diff = QPainter(diff_pixmap)
        try:
            white = QColor('white')
            diff.fillRect(0, 0, actual_image.width(), actual_image.height(),
                          white)
            for x in range(actual_image.width()):
                for y in range(actual_image.height()):
                    actual_colour = actual_image.pixelColor(x, y)
                    expected_colour = expected_image.pixelColor(x, y)
                    diff.setPen(
                        self.diff_colour(actual_colour, expected_colour, x, y))
                    diff.drawPoint(x, y)
        finally:
            diff.end()
        diff_image: QImage = diff.device().toImage()

        display_diff(actual_image, diff_image, expected_image,
                     self.different_pixels)

        if self.different_pixels == 0:
            return
        actual_image.save(str(self.work_dir / (self.name + '_actual.png')))
        expected_image.save(str(self.work_dir / (self.name + '_expected.png')))
        diff_path = self.work_dir / (self.name + '_diff.png')
        is_saved = diff_image.save(str(diff_path))
        diff_width = self.diff_max_x - self.diff_min_x + 1
        diff_height = self.diff_max_y - self.diff_min_y + 1
        diff_section = QImage(diff_width, diff_height, QImage.Format_RGB32)
        diff_section_painter = QPainter(diff_section)
        try:
            diff_section_painter.drawPixmap(0, 0, diff_width, diff_height,
                                            QPixmap.fromImage(diff_image),
                                            self.diff_min_x, self.diff_min_y,
                                            diff_width, diff_height)
        finally:
            diff_section_painter.end()
        message = f'Found {self.different_pixels} different pixels.'
        assert self.different_pixels == 0, message
示例#3
0
def render_display(display: GameDisplay,
                   painter: QPainter,
                   is_closed: bool = True):
    """ Check scene size, render, then clear scene.

    You have to clear the scene to avoid a crash after running several unit
    tests.
    :param display: display widget whose children contain a QGraphicsView to
        render.
    :param painter: a canvas to render on
    :param is_closed: True if the display should be closed after rendering. Be
        sure to close the display before exiting the test, if it contains any
        items with reference cycles back to the scene.
    """
    __tracebackhide__ = True
    try:
        for child in display.children():
            if isinstance(child, QGraphicsView):
                view = child
                break
        else:
            raise ValueError("No QGraphicsView in display's children.")

        view.grab()  # Force layout to recalculate, if needed.
        scene_size = view.contentsRect().size()
        device = painter.device()
        assert isinstance(device, QPixmap)
        painter_size = device.size()
        if scene_size != painter_size:
            display_size = find_display_size(display, view, painter_size)
            message = (f"Try resizing display to "
                       f"{display_size.width()}x{display_size.height()}.")
            painter.drawText(
                QRect(0, 0, painter_size.width(), painter_size.height()),
                Qt.AlignCenter | Qt.TextWordWrap,  # type: ignore
                message)
            return
        assert scene_size == painter_size
        view.scene().render(painter)
    finally:
        if is_closed:
            display.close()
示例#4
0
class PixmapDiffer:
    def __init__(self):
        self.name = None
        self.actual_pixmap = self.expected_pixmap = None
        self.actual = self.expected = None
        self.different_pixels = 0
        self.diff_min_x = self.diff_min_y = None
        self.diff_max_x = self.diff_max_y = None
        self.max_diff = 0

        self.names = set()

        self.work_dir: Path = (Path(__file__).parent.parent / 'tests' /
                               'pixmap_diffs')
        self.work_dir.mkdir(exist_ok=True)
        for work_file in self.work_dir.iterdir():
            if work_file.name == 'README.md':
                continue
            assert work_file.suffix == '.png', work_file
            work_file.unlink()

    @contextmanager
    def create_painters(self,
                        width: int,
                        height: int,
                        name: str,
                        max_diff: int = 0
                        ) -> typing.Iterator[typing.Tuple[QPainter, QPainter]]:
        self.max_diff = max_diff
        try:
            yield self.start(width, height, name)
        finally:
            self.end()
        self.assert_equal()

    def start(self, width: int, height: int,
              name: str) -> typing.Tuple[QPainter, QPainter]:
        """ Create painters for the actual and expected images.

        Caller must either call end() or assert_equal() to properly clean up
        the painters and pixmaps. Caller may either paint through the returned
        painters, or call the end() method and create a new painter on the
        same device. Order matters, though!
        """
        assert name not in self.names, f'Duplicate name: {name!r}.'
        self.names.add(name)
        self.name = name

        white = QColor('white')
        self.actual_pixmap = QPixmap(width, height)
        self.actual_pixmap.fill(white)
        self.actual = QPainter(self.actual_pixmap)
        self.expected_pixmap = QPixmap(width, height)
        self.expected_pixmap.fill(white)
        self.expected = QPainter(self.expected_pixmap)

        return self.actual, self.expected

    def end(self):
        if self.actual and self.actual.isActive():
            self.actual.end()
        if self.expected and self.expected.isActive():
            self.expected.end()

    def assert_equal(self):
        __tracebackhide__ = True
        self.end()
        self.different_pixels = 0
        actual_image: QImage = self.actual.device().toImage()
        expected_image: QImage = self.expected.device().toImage()
        diff_pixmap = QPixmap(actual_image.width(), actual_image.height())
        diff = QPainter(diff_pixmap)
        try:
            white = QColor('white')
            diff.fillRect(0, 0, actual_image.width(), actual_image.height(),
                          white)
            for x in range(actual_image.width()):
                for y in range(actual_image.height()):
                    actual_colour = actual_image.pixelColor(x, y)
                    expected_colour = expected_image.pixelColor(x, y)
                    diff.setPen(
                        self.diff_colour(actual_colour, expected_colour, x, y))
                    diff.drawPoint(x, y)
        finally:
            diff.end()
        diff_image: QImage = diff.device().toImage()

        display_diff(actual_image, diff_image, expected_image,
                     self.different_pixels)

        if self.different_pixels == 0:
            return
        actual_image.save(str(self.work_dir / (self.name + '_actual.png')))
        expected_image.save(str(self.work_dir / (self.name + '_expected.png')))
        diff_path = self.work_dir / (self.name + '_diff.png')
        is_saved = diff_image.save(str(diff_path))
        diff_width = self.diff_max_x - self.diff_min_x + 1
        diff_height = self.diff_max_y - self.diff_min_y + 1
        diff_section = QImage(diff_width, diff_height, QImage.Format_RGB32)
        diff_section_painter = QPainter(diff_section)
        try:
            diff_section_painter.drawPixmap(0, 0, diff_width, diff_height,
                                            QPixmap.fromImage(diff_image),
                                            self.diff_min_x, self.diff_min_y,
                                            diff_width, diff_height)
        finally:
            diff_section_painter.end()
        # To see an image dumped in the Travis CI log, copy the text from the
        # log, and paste it in test_pixmap_differ.test_decode_image.
        print(f'Encoded image of differing section '
              f'({self.diff_min_x}, {self.diff_min_y}) - '
              f'({self.diff_max_x}, {self.diff_max_y}):')
        print(encode_image(diff_section))
        message = f'Found {self.different_pixels} different pixels, '
        message += f'see' if is_saved else 'could not write'
        message += f' {diff_path.relative_to(Path(__file__).parent.parent)}.'
        assert self.different_pixels == 0, message

    def diff_colour(self, actual_colour: QColor, expected_colour: QColor,
                    x: int, y: int):
        diff_size = (abs(actual_colour.red() - expected_colour.red()) +
                     abs(actual_colour.green() - expected_colour.green()) +
                     abs(actual_colour.blue() - expected_colour.blue()))
        if diff_size <= self.max_diff:
            diff_colour = actual_colour.toRgb()
            diff_colour.setAlpha(diff_colour.alpha() // 3)
            return diff_colour
        if self.different_pixels == 0:
            self.diff_min_x = self.diff_max_x = x
            self.diff_min_y = self.diff_max_y = y
        else:
            self.diff_min_x = min(self.diff_min_x, x)
            self.diff_max_x = max(self.diff_max_x, x)
            self.diff_min_y = min(self.diff_min_y, y)
            self.diff_max_y = max(self.diff_max_y, y)

        self.different_pixels += 1
        # Colour
        dr = 0xff
        dg = (actual_colour.green() + expected_colour.green()) // 5
        db = (actual_colour.blue() + expected_colour.blue()) // 5

        # Opacity
        da = 0xff
        return QColor(dr, dg, db, da)