# -*- coding: utf-8 -*-
#
# New BSD license
#
# Copyright (c) DR0ID
# This file is part of spritesheetlib
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
# * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# * Neither the name of the <organization> nor the
# names of its contributors may be used to endorse or promote products
# derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL DR0ID BE LIABLE FOR ANY
# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
TODO: module description
Versioning scheme based on: http://en.wikipedia.org/wiki/Versioning#Designating_development_stage
::
+-- api change, probably incompatible with older versions
| +-- enhancements but no api change
| |
major.minor[.build[.revision]]
| |
| +-|* x for x bugfixes
|
+-|* 0 for alpha (status)
|* 1 for beta (status)
|* 2 for release candidate
|* 3 for (public) release
.. versionchanged:: 0.0.0.0
initial version
"""
import random
import unittest
import logging
import warnings
warnings.simplefilter('default') # make warnings visible for developers
import spritesheetlib as mut # module under test
import tests.datadriventestingdecorators as ddtd
from spritesheetlib import SpritesheetLib10
from spritesheetlib import FileInfo
__version__ = '1.0.3.0'
# for easy comparison as in sys.version_info but digits only
__version_info__ = tuple([int(d) for d in __version__.split('.')])
__author__ = "DR0ID"
__email__ = "dr0iddr0id [at] gmail [dot] com"
__copyright__ = "DR0ID @ 2014"
__credits__ = ["DR0ID"] # list of contributors
__maintainer__ = "DR0ID"
__license__ = "New BSD license"
V1ELEMENTS = SpritesheetLib10.ELEMENTS
V1PROPERTIES = SpritesheetLib10.PROPERTIES
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
logger.level = logging.DEBUG
[docs]class TestVersions(unittest.TestCase):
"""
This class test the version of this test module to be equal to the version of the module that is tested.
"""
[docs] def test_version_should_be_equal_to_mut_version(self):
"""
Tests if the module versions are equal.
"""
# arrange / act / verify
self.assertTrue(mut.__version_info__ == __version_info__,
"version of module under test should match version of this tests !")
[docs]class TestData(object):
"""
Contains all sprite definitions used for testing (valid and invalid ones).
"""
SDEF_GRID_2X2 = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "out.png.sdef",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: 0,
V1ELEMENTS.PROPERTIES: {V1PROPERTIES.COLUMN: 0, V1PROPERTIES.ROW: 0},
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 32], [0, 32]],
V1ELEMENTS.ANCHOR: [10, 10]},
{V1ELEMENTS.GID: 1,
V1ELEMENTS.PROPERTIES: {V1PROPERTIES.COLUMN: 1, V1PROPERTIES.ROW: 0},
V1ELEMENTS.POINTS: [[32, 0], [64, 0], [64, 32], [32, 32]], },
{V1ELEMENTS.GID: 2,
V1ELEMENTS.PROPERTIES: {V1PROPERTIES.COLUMN: 0, V1PROPERTIES.ROW: 1},
V1ELEMENTS.POINTS: [[0, 32], [32, 32], [32, 64], [0, 64]], },
{V1ELEMENTS.GID: 3,
V1ELEMENTS.PROPERTIES: {V1PROPERTIES.COLUMN: 1, V1PROPERTIES.ROW: 1},
V1ELEMENTS.POINTS: [[32, 32], [64, 32], [64, 64], [32, 64]], }, ]}
SDEF_GRID_2X2_TEST = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "test.sdef.png.sdef",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 32], [0, 32]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[32, 0], [64, 0], [64, 32], [32, 32]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[0, 32], [32, 32], [32, 64], [0, 64]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[32, 32], [64, 32], [64, 64], [32, 64]], }, ]}
SDEF_GRID_2X2_MARGIN_33 = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "out.png.sdef",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: 0,
V1ELEMENTS.PROPERTIES: {V1PROPERTIES.COLUMN: 0, V1PROPERTIES.ROW: 0},
V1ELEMENTS.ANCHOR: [10, 10],
V1ELEMENTS.POINTS: [[0 + 33, 0 + 33], [32 + 33, 0 + 33], [32 + 33, 32 + 33],
[0 + 33, 32 + 33]], },
{V1ELEMENTS.GID: 1,
V1ELEMENTS.PROPERTIES: {V1PROPERTIES.COLUMN: 1, V1PROPERTIES.ROW: 0},
V1ELEMENTS.POINTS: [[32 + 33, 0 + 33], [64 + 33, 0 + 33], [64 + 33, 32 + 33],
[32 + 33, 32 + 33]], },
{V1ELEMENTS.GID: 2,
V1ELEMENTS.PROPERTIES: {V1PROPERTIES.COLUMN: 0, V1PROPERTIES.ROW: 1},
V1ELEMENTS.POINTS: [[0 + 33, 32 + 33], [32 + 33, 32 + 33], [32 + 33, 64 + 33],
[0 + 33, 64 + 33]], },
{V1ELEMENTS.GID: 3,
V1ELEMENTS.PROPERTIES: {V1PROPERTIES.COLUMN: 1, V1PROPERTIES.ROW: 1},
V1ELEMENTS.POINTS: [[32 + 33, 32 + 33], [64 + 33, 32 + 33], [64 + 33, 64 + 33],
[32 + 33, 64 + 33]], }, ]}
SDEF_GRID_2X2_SPECIAL_MARGIN = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "out.png.sdef",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 32], [0, 32]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[32, 0 - 13], [64, 0 - 13], [64, 32], [32, 32]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[0 - 17, 32], [32, 32], [32, 64], [0 - 17, 64]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[32, 32], [64, 32], [64, 64], [32, 64]], }, ]}
SDEF_GRID_2X2_SPECIAL_MARGIN_5 = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "out.png.sdef",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0 + 22, 0 + 18], [32 + 22, 0 + 18], [32 + 22, 32 + 18],
[0 + 22, 32 + 18]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[32 + 22, 0 - 13 + 18], [64 + 22, 0 - 13 + 18],
[64 + 22, 32 + 18], [32 + 22, 32 + 18]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[0 - 17 + 22, 32 + 18], [32 + 22, 32 + 18],
[32 + 22, 64 + 18], [0 - 17 + 22, 64 + 18]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[32 + 22, 32 + 18], [64 + 22, 32 + 18],
[64 + 22, 64 + 18], [32 + 22, 64 + 18]], }, ]}
SDEF_GRID_10X10 = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "out.png.sdef",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0 * 32, 0 * 32], [32 + 0 * 32, 0 * 32],
[32 + 0 * 32, 32 + 0 * 32],
[0 * 32, 32 + 0 * 32]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[1 * 32, 0 * 32], [32 + 1 * 32, 0 * 32],
[32 + 1 * 32, 32 + 0 * 32],
[1 * 32, 32 + 0 * 32]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[2 * 32, 0 * 32], [32 + 2 * 32, 0 * 32],
[32 + 2 * 32, 32 + 0 * 32],
[2 * 32, 32 + 0 * 32]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[3 * 32, 0 * 32], [32 + 3 * 32, 0 * 32],
[32 + 3 * 32, 32 + 0 * 32],
[3 * 32, 32 + 0 * 32]], },
{V1ELEMENTS.GID: "004",
V1ELEMENTS.POINTS: [[4 * 32, 0 * 32], [32 + 4 * 32, 0 * 32],
[32 + 4 * 32, 32 + 0 * 32],
[4 * 32, 32 + 0 * 32]], },
{V1ELEMENTS.GID: "005",
V1ELEMENTS.POINTS: [[5 * 32, 0 * 32], [32 + 5 * 32, 0 * 32],
[32 + 5 * 32, 32 + 0 * 32],
[5 * 32, 32 + 0 * 32]], },
{V1ELEMENTS.GID: "006",
V1ELEMENTS.POINTS: [[6 * 32, 0 * 32], [32 + 6 * 32, 0 * 32],
[32 + 6 * 32, 32 + 0 * 32],
[6 * 32, 32 + 0 * 32]], },
{V1ELEMENTS.GID: "007",
V1ELEMENTS.POINTS: [[7 * 32, 0 * 32], [32 + 7 * 32, 0 * 32],
[32 + 7 * 32, 32 + 0 * 32],
[7 * 32, 32 + 0 * 32]], },
{V1ELEMENTS.GID: "008",
V1ELEMENTS.POINTS: [[8 * 32, 0 * 32], [32 + 8 * 32, 0 * 32],
[32 + 8 * 32, 32 + 0 * 32],
[8 * 32, 32 + 0 * 32]], },
{V1ELEMENTS.GID: "009",
V1ELEMENTS.POINTS: [[9 * 32, 0 * 32], [32 + 9 * 32, 0 * 32],
[32 + 9 * 32, 32 + 0 * 32],
[9 * 32, 32 + 0 * 32]], },
{V1ELEMENTS.GID: "010",
V1ELEMENTS.POINTS: [[0 * 32, 1 * 32], [32 + 0 * 32, 1 * 32],
[32 + 0 * 32, 32 + 1 * 32],
[0 * 32, 32 + 1 * 32]], },
{V1ELEMENTS.GID: "011",
V1ELEMENTS.POINTS: [[1 * 32, 1 * 32], [32 + 1 * 32, 1 * 32],
[32 + 1 * 32, 32 + 1 * 32],
[1 * 32, 32 + 1 * 32]], },
{V1ELEMENTS.GID: "012",
V1ELEMENTS.POINTS: [[2 * 32, 1 * 32], [32 + 2 * 32, 1 * 32],
[32 + 2 * 32, 32 + 1 * 32],
[2 * 32, 32 + 1 * 32]], },
{V1ELEMENTS.GID: "013",
V1ELEMENTS.POINTS: [[3 * 32, 1 * 32], [32 + 3 * 32, 1 * 32],
[32 + 3 * 32, 32 + 1 * 32],
[3 * 32, 32 + 1 * 32]], },
{V1ELEMENTS.GID: "014",
V1ELEMENTS.POINTS: [[4 * 32, 1 * 32], [32 + 4 * 32, 1 * 32],
[32 + 4 * 32, 32 + 1 * 32],
[4 * 32, 32 + 1 * 32]], },
{V1ELEMENTS.GID: "015",
V1ELEMENTS.POINTS: [[5 * 32, 1 * 32], [32 + 5 * 32, 1 * 32],
[32 + 5 * 32, 32 + 1 * 32],
[5 * 32, 32 + 1 * 32]], },
{V1ELEMENTS.GID: "016",
V1ELEMENTS.POINTS: [[6 * 32, 1 * 32], [32 + 6 * 32, 1 * 32],
[32 + 6 * 32, 32 + 1 * 32],
[6 * 32, 32 + 1 * 32]], },
{V1ELEMENTS.GID: "017",
V1ELEMENTS.POINTS: [[7 * 32, 1 * 32], [32 + 7 * 32, 1 * 32],
[32 + 7 * 32, 32 + 1 * 32],
[7 * 32, 32 + 1 * 32]], },
{V1ELEMENTS.GID: "018",
V1ELEMENTS.POINTS: [[8 * 32, 1 * 32], [32 + 8 * 32, 1 * 32],
[32 + 8 * 32, 32 + 1 * 32],
[8 * 32, 32 + 1 * 32]], },
{V1ELEMENTS.GID: "019",
V1ELEMENTS.POINTS: [[9 * 32, 1 * 32], [32 + 9 * 32, 1 * 32],
[32 + 9 * 32, 32 + 1 * 32],
[9 * 32, 32 + 1 * 32]], },
{V1ELEMENTS.GID: "020",
V1ELEMENTS.POINTS: [[0 * 32, 2 * 32], [32 + 0 * 32, 2 * 32],
[32 + 0 * 32, 32 + 2 * 32],
[0 * 32, 32 + 2 * 32]], },
{V1ELEMENTS.GID: "021",
V1ELEMENTS.POINTS: [[1 * 32, 2 * 32], [32 + 1 * 32, 2 * 32],
[32 + 1 * 32, 32 + 2 * 32],
[1 * 32, 32 + 2 * 32]], },
{V1ELEMENTS.GID: "022",
V1ELEMENTS.POINTS: [[2 * 32, 2 * 32], [32 + 2 * 32, 2 * 32],
[32 + 2 * 32, 32 + 2 * 32],
[2 * 32, 32 + 2 * 32]], },
{V1ELEMENTS.GID: "023",
V1ELEMENTS.POINTS: [[3 * 32, 2 * 32], [32 + 3 * 32, 2 * 32],
[32 + 3 * 32, 32 + 2 * 32],
[3 * 32, 32 + 2 * 32]], },
{V1ELEMENTS.GID: "024",
V1ELEMENTS.POINTS: [[4 * 32, 2 * 32], [32 + 4 * 32, 2 * 32],
[32 + 4 * 32, 32 + 2 * 32],
[4 * 32, 32 + 2 * 32]], },
{V1ELEMENTS.GID: "025",
V1ELEMENTS.POINTS: [[5 * 32, 2 * 32], [32 + 5 * 32, 2 * 32],
[32 + 5 * 32, 32 + 2 * 32],
[5 * 32, 32 + 2 * 32]], },
{V1ELEMENTS.GID: "026",
V1ELEMENTS.POINTS: [[6 * 32, 2 * 32], [32 + 6 * 32, 2 * 32],
[32 + 6 * 32, 32 + 2 * 32],
[6 * 32, 32 + 2 * 32]], },
{V1ELEMENTS.GID: "027",
V1ELEMENTS.POINTS: [[7 * 32, 2 * 32], [32 + 7 * 32, 2 * 32],
[32 + 7 * 32, 32 + 2 * 32],
[7 * 32, 32 + 2 * 32]], },
{V1ELEMENTS.GID: "028",
V1ELEMENTS.POINTS: [[8 * 32, 2 * 32], [32 + 8 * 32, 2 * 32],
[32 + 8 * 32, 32 + 2 * 32],
[8 * 32, 32 + 2 * 32]], },
{V1ELEMENTS.GID: "029",
V1ELEMENTS.POINTS: [[9 * 32, 2 * 32], [32 + 9 * 32, 2 * 32],
[32 + 9 * 32, 32 + 2 * 32],
[9 * 32, 32 + 2 * 32]], },
{V1ELEMENTS.GID: "030",
V1ELEMENTS.POINTS: [[0 * 32, 3 * 32], [32 + 0 * 32, 3 * 32],
[32 + 0 * 32, 32 + 3 * 32],
[0 * 32, 32 + 3 * 32]], },
{V1ELEMENTS.GID: "031",
V1ELEMENTS.POINTS: [[1 * 32, 3 * 32], [32 + 1 * 32, 3 * 32],
[32 + 1 * 32, 32 + 3 * 32],
[1 * 32, 32 + 3 * 32]], },
{V1ELEMENTS.GID: "032",
V1ELEMENTS.POINTS: [[2 * 32, 3 * 32], [32 + 2 * 32, 3 * 32],
[32 + 2 * 32, 32 + 3 * 32],
[2 * 32, 32 + 3 * 32]], },
{V1ELEMENTS.GID: "033",
V1ELEMENTS.POINTS: [[3 * 32, 3 * 32], [32 + 3 * 32, 3 * 32],
[32 + 3 * 32, 32 + 3 * 32],
[3 * 32, 32 + 3 * 32]], },
{V1ELEMENTS.GID: "034",
V1ELEMENTS.POINTS: [[4 * 32, 3 * 32], [32 + 4 * 32, 3 * 32],
[32 + 4 * 32, 32 + 3 * 32],
[4 * 32, 32 + 3 * 32]], },
{V1ELEMENTS.GID: "035",
V1ELEMENTS.POINTS: [[5 * 32, 3 * 32], [32 + 5 * 32, 3 * 32],
[32 + 5 * 32, 32 + 3 * 32],
[5 * 32, 32 + 3 * 32]], },
{V1ELEMENTS.GID: "036",
V1ELEMENTS.POINTS: [[6 * 32, 3 * 32], [32 + 6 * 32, 3 * 32],
[32 + 6 * 32, 32 + 3 * 32],
[6 * 32, 32 + 3 * 32]], },
{V1ELEMENTS.GID: "037",
V1ELEMENTS.POINTS: [[7 * 32, 3 * 32], [32 + 7 * 32, 3 * 32],
[32 + 7 * 32, 32 + 3 * 32],
[7 * 32, 32 + 3 * 32]], },
{V1ELEMENTS.GID: "038",
V1ELEMENTS.POINTS: [[8 * 32, 3 * 32], [32 + 8 * 32, 3 * 32],
[32 + 8 * 32, 32 + 3 * 32],
[8 * 32, 32 + 3 * 32]], },
{V1ELEMENTS.GID: "039",
V1ELEMENTS.POINTS: [[9 * 32, 3 * 32], [32 + 9 * 32, 3 * 32],
[32 + 9 * 32, 32 + 3 * 32],
[9 * 32, 32 + 3 * 32]], },
{V1ELEMENTS.GID: "040",
V1ELEMENTS.POINTS: [[0 * 32, 4 * 32], [32 + 0 * 32, 4 * 32],
[32 + 0 * 32, 32 + 4 * 32],
[0 * 32, 32 + 4 * 32]], },
{V1ELEMENTS.GID: "041",
V1ELEMENTS.POINTS: [[1 * 32, 4 * 32], [32 + 1 * 32, 4 * 32],
[32 + 1 * 32, 32 + 4 * 32],
[1 * 32, 32 + 4 * 32]], },
{V1ELEMENTS.GID: "042",
V1ELEMENTS.POINTS: [[2 * 32, 4 * 32], [32 + 2 * 32, 4 * 32],
[32 + 2 * 32, 32 + 4 * 32],
[2 * 32, 32 + 4 * 32]], },
{V1ELEMENTS.GID: "043",
V1ELEMENTS.POINTS: [[3 * 32, 4 * 32], [32 + 3 * 32, 4 * 32],
[32 + 3 * 32, 32 + 4 * 32],
[3 * 32, 32 + 4 * 32]], },
{V1ELEMENTS.GID: "044",
V1ELEMENTS.POINTS: [[4 * 32, 4 * 32], [32 + 4 * 32, 4 * 32],
[32 + 4 * 32, 32 + 4 * 32],
[4 * 32, 32 + 4 * 32]], },
{V1ELEMENTS.GID: "045",
V1ELEMENTS.POINTS: [[5 * 32, 4 * 32], [32 + 5 * 32, 4 * 32],
[32 + 5 * 32, 32 + 4 * 32],
[5 * 32, 32 + 4 * 32]], },
{V1ELEMENTS.GID: "046",
V1ELEMENTS.POINTS: [[6 * 32, 4 * 32], [32 + 6 * 32, 4 * 32],
[32 + 6 * 32, 32 + 4 * 32],
[6 * 32, 32 + 4 * 32]], },
{V1ELEMENTS.GID: "047",
V1ELEMENTS.POINTS: [[7 * 32, 4 * 32], [32 + 7 * 32, 4 * 32],
[32 + 7 * 32, 32 + 4 * 32],
[7 * 32, 32 + 4 * 32]], },
{V1ELEMENTS.GID: "048",
V1ELEMENTS.POINTS: [[8 * 32, 4 * 32], [32 + 8 * 32, 4 * 32],
[32 + 8 * 32, 32 + 4 * 32],
[8 * 32, 32 + 4 * 32]], },
{V1ELEMENTS.GID: "049",
V1ELEMENTS.POINTS: [[9 * 32, 4 * 32], [32 + 9 * 32, 4 * 32],
[32 + 9 * 32, 32 + 4 * 32],
[9 * 32, 32 + 4 * 32]], },
{V1ELEMENTS.GID: "050",
V1ELEMENTS.POINTS: [[0 * 32, 5 * 32], [32 + 0 * 32, 5 * 32],
[32 + 0 * 32, 32 + 5 * 32],
[0 * 32, 32 + 5 * 32]], },
{V1ELEMENTS.GID: "051",
V1ELEMENTS.POINTS: [[1 * 32, 5 * 32], [32 + 1 * 32, 5 * 32],
[32 + 1 * 32, 32 + 5 * 32],
[1 * 32, 32 + 5 * 32]], },
{V1ELEMENTS.GID: "052",
V1ELEMENTS.POINTS: [[2 * 32, 5 * 32], [32 + 2 * 32, 5 * 32],
[32 + 2 * 32, 32 + 5 * 32],
[2 * 32, 32 + 5 * 32]], },
{V1ELEMENTS.GID: "053",
V1ELEMENTS.POINTS: [[3 * 32, 5 * 32], [32 + 3 * 32, 5 * 32],
[32 + 3 * 32, 32 + 5 * 32],
[3 * 32, 32 + 5 * 32]], },
{V1ELEMENTS.GID: "054",
V1ELEMENTS.POINTS: [[4 * 32, 5 * 32], [32 + 4 * 32, 5 * 32],
[32 + 4 * 32, 32 + 5 * 32],
[4 * 32, 32 + 5 * 32]], },
{V1ELEMENTS.GID: "055",
V1ELEMENTS.POINTS: [[5 * 32, 5 * 32], [32 + 5 * 32, 5 * 32],
[32 + 5 * 32, 32 + 5 * 32],
[5 * 32, 32 + 5 * 32]], },
{V1ELEMENTS.GID: "056",
V1ELEMENTS.POINTS: [[6 * 32, 5 * 32], [32 + 6 * 32, 5 * 32],
[32 + 6 * 32, 32 + 5 * 32],
[6 * 32, 32 + 5 * 32]], },
{V1ELEMENTS.GID: "057",
V1ELEMENTS.POINTS: [[7 * 32, 5 * 32], [32 + 7 * 32, 5 * 32],
[32 + 7 * 32, 32 + 5 * 32],
[7 * 32, 32 + 5 * 32]], },
{V1ELEMENTS.GID: "058",
V1ELEMENTS.POINTS: [[8 * 32, 5 * 32], [32 + 8 * 32, 5 * 32],
[32 + 8 * 32, 32 + 5 * 32],
[8 * 32, 32 + 5 * 32]], },
{V1ELEMENTS.GID: "059",
V1ELEMENTS.POINTS: [[9 * 32, 5 * 32], [32 + 9 * 32, 5 * 32],
[32 + 9 * 32, 32 + 5 * 32],
[9 * 32, 32 + 5 * 32]], },
{V1ELEMENTS.GID: "060",
V1ELEMENTS.POINTS: [[0 * 32, 6 * 32], [32 + 0 * 32, 6 * 32],
[32 + 0 * 32, 32 + 6 * 32],
[0 * 32, 32 + 6 * 32]], },
{V1ELEMENTS.GID: "061",
V1ELEMENTS.POINTS: [[1 * 32, 6 * 32], [32 + 1 * 32, 6 * 32],
[32 + 1 * 32, 32 + 6 * 32],
[1 * 32, 32 + 6 * 32]], },
{V1ELEMENTS.GID: "062",
V1ELEMENTS.POINTS: [[2 * 32, 6 * 32], [32 + 2 * 32, 6 * 32],
[32 + 2 * 32, 32 + 6 * 32],
[2 * 32, 32 + 6 * 32]], },
{V1ELEMENTS.GID: "063",
V1ELEMENTS.POINTS: [[3 * 32, 6 * 32], [32 + 3 * 32, 6 * 32],
[32 + 3 * 32, 32 + 6 * 32],
[3 * 32, 32 + 6 * 32]], },
{V1ELEMENTS.GID: "064",
V1ELEMENTS.POINTS: [[4 * 32, 6 * 32], [32 + 4 * 32, 6 * 32],
[32 + 4 * 32, 32 + 6 * 32],
[4 * 32, 32 + 6 * 32]], },
{V1ELEMENTS.GID: "065",
V1ELEMENTS.POINTS: [[5 * 32, 6 * 32], [32 + 5 * 32, 6 * 32],
[32 + 5 * 32, 32 + 6 * 32],
[5 * 32, 32 + 6 * 32]], },
{V1ELEMENTS.GID: "066",
V1ELEMENTS.POINTS: [[6 * 32, 6 * 32], [32 + 6 * 32, 6 * 32],
[32 + 6 * 32, 32 + 6 * 32],
[6 * 32, 32 + 6 * 32]], },
{V1ELEMENTS.GID: "067",
V1ELEMENTS.POINTS: [[7 * 32, 6 * 32], [32 + 7 * 32, 6 * 32],
[32 + 7 * 32, 32 + 6 * 32],
[7 * 32, 32 + 6 * 32]], },
{V1ELEMENTS.GID: "068",
V1ELEMENTS.POINTS: [[8 * 32, 6 * 32], [32 + 8 * 32, 6 * 32],
[32 + 8 * 32, 32 + 6 * 32],
[8 * 32, 32 + 6 * 32]], },
{V1ELEMENTS.GID: "069",
V1ELEMENTS.POINTS: [[9 * 32, 6 * 32], [32 + 9 * 32, 6 * 32],
[32 + 9 * 32, 32 + 6 * 32],
[9 * 32, 32 + 6 * 32]], },
{V1ELEMENTS.GID: "070",
V1ELEMENTS.POINTS: [[0 * 32, 7 * 32], [32 + 0 * 32, 7 * 32],
[32 + 0 * 32, 32 + 7 * 32],
[0 * 32, 32 + 7 * 32]], },
{V1ELEMENTS.GID: "071",
V1ELEMENTS.POINTS: [[1 * 32, 7 * 32], [32 + 1 * 32, 7 * 32],
[32 + 1 * 32, 32 + 7 * 32],
[1 * 32, 32 + 7 * 32]], },
{V1ELEMENTS.GID: "072",
V1ELEMENTS.POINTS: [[2 * 32, 7 * 32], [32 + 2 * 32, 7 * 32],
[32 + 2 * 32, 32 + 7 * 32],
[2 * 32, 32 + 7 * 32]], },
{V1ELEMENTS.GID: "073",
V1ELEMENTS.POINTS: [[3 * 32, 7 * 32], [32 + 3 * 32, 7 * 32],
[32 + 3 * 32, 32 + 7 * 32],
[3 * 32, 32 + 7 * 32]], },
{V1ELEMENTS.GID: "074",
V1ELEMENTS.POINTS: [[4 * 32, 7 * 32], [32 + 4 * 32, 7 * 32],
[32 + 4 * 32, 32 + 7 * 32],
[4 * 32, 32 + 7 * 32]], },
{V1ELEMENTS.GID: "075",
V1ELEMENTS.POINTS: [[5 * 32, 7 * 32], [32 + 5 * 32, 7 * 32],
[32 + 5 * 32, 32 + 7 * 32],
[5 * 32, 32 + 7 * 32]], },
{V1ELEMENTS.GID: "076",
V1ELEMENTS.POINTS: [[6 * 32, 7 * 32], [32 + 6 * 32, 7 * 32],
[32 + 6 * 32, 32 + 7 * 32],
[6 * 32, 32 + 7 * 32]], },
{V1ELEMENTS.GID: "077",
V1ELEMENTS.POINTS: [[7 * 32, 7 * 32], [32 + 7 * 32, 7 * 32],
[32 + 7 * 32, 32 + 7 * 32],
[7 * 32, 32 + 7 * 32]], },
{V1ELEMENTS.GID: "078",
V1ELEMENTS.POINTS: [[8 * 32, 7 * 32], [32 + 8 * 32, 7 * 32],
[32 + 8 * 32, 32 + 7 * 32],
[8 * 32, 32 + 7 * 32]], },
{V1ELEMENTS.GID: "079",
V1ELEMENTS.POINTS: [[9 * 32, 7 * 32], [32 + 9 * 32, 7 * 32],
[32 + 9 * 32, 32 + 7 * 32],
[9 * 32, 32 + 7 * 32]], },
{V1ELEMENTS.GID: "080",
V1ELEMENTS.POINTS: [[0 * 32, 8 * 32], [32 + 0 * 32, 8 * 32],
[32 + 0 * 32, 32 + 8 * 32],
[0 * 32, 32 + 8 * 32]], },
{V1ELEMENTS.GID: "081",
V1ELEMENTS.POINTS: [[1 * 32, 8 * 32], [32 + 1 * 32, 8 * 32],
[32 + 1 * 32, 32 + 8 * 32],
[1 * 32, 32 + 8 * 32]], },
{V1ELEMENTS.GID: "082",
V1ELEMENTS.POINTS: [[2 * 32, 8 * 32], [32 + 2 * 32, 8 * 32],
[32 + 2 * 32, 32 + 8 * 32],
[2 * 32, 32 + 8 * 32]], },
{V1ELEMENTS.GID: "083",
V1ELEMENTS.POINTS: [[3 * 32, 8 * 32], [32 + 3 * 32, 8 * 32],
[32 + 3 * 32, 32 + 8 * 32],
[3 * 32, 32 + 8 * 32]], },
{V1ELEMENTS.GID: "084",
V1ELEMENTS.POINTS: [[4 * 32, 8 * 32], [32 + 4 * 32, 8 * 32],
[32 + 4 * 32, 32 + 8 * 32],
[4 * 32, 32 + 8 * 32]], },
{V1ELEMENTS.GID: "085",
V1ELEMENTS.POINTS: [[5 * 32, 8 * 32], [32 + 5 * 32, 8 * 32],
[32 + 5 * 32, 32 + 8 * 32],
[5 * 32, 32 + 8 * 32]], },
{V1ELEMENTS.GID: "086",
V1ELEMENTS.POINTS: [[6 * 32, 8 * 32], [32 + 6 * 32, 8 * 32],
[32 + 6 * 32, 32 + 8 * 32],
[6 * 32, 32 + 8 * 32]], },
{V1ELEMENTS.GID: "087",
V1ELEMENTS.POINTS: [[7 * 32, 8 * 32], [32 + 7 * 32, 8 * 32],
[32 + 7 * 32, 32 + 8 * 32],
[7 * 32, 32 + 8 * 32]], },
{V1ELEMENTS.GID: "088",
V1ELEMENTS.POINTS: [[8 * 32, 8 * 32], [32 + 8 * 32, 8 * 32],
[32 + 8 * 32, 32 + 8 * 32],
[8 * 32, 32 + 8 * 32]], },
{V1ELEMENTS.GID: "089",
V1ELEMENTS.POINTS: [[9 * 32, 8 * 32], [32 + 9 * 32, 8 * 32],
[32 + 9 * 32, 32 + 8 * 32],
[9 * 32, 32 + 8 * 32]], },
{V1ELEMENTS.GID: "090",
V1ELEMENTS.POINTS: [[0 * 32, 9 * 32], [32 + 0 * 32, 9 * 32],
[32 + 0 * 32, 32 + 9 * 32],
[0 * 32, 32 + 9 * 32]], },
{V1ELEMENTS.GID: "091",
V1ELEMENTS.POINTS: [[1 * 32, 9 * 32], [32 + 1 * 32, 9 * 32],
[32 + 1 * 32, 32 + 9 * 32],
[1 * 32, 32 + 9 * 32]], },
{V1ELEMENTS.GID: "092",
V1ELEMENTS.POINTS: [[2 * 32, 9 * 32], [32 + 2 * 32, 9 * 32],
[32 + 2 * 32, 32 + 9 * 32],
[2 * 32, 32 + 9 * 32]], },
{V1ELEMENTS.GID: "093",
V1ELEMENTS.POINTS: [[3 * 32, 9 * 32], [32 + 3 * 32, 9 * 32],
[32 + 3 * 32, 32 + 9 * 32],
[3 * 32, 32 + 9 * 32]], },
{V1ELEMENTS.GID: "094",
V1ELEMENTS.POINTS: [[4 * 32, 9 * 32], [32 + 4 * 32, 9 * 32],
[32 + 4 * 32, 32 + 9 * 32],
[4 * 32, 32 + 9 * 32]], },
{V1ELEMENTS.GID: "095",
V1ELEMENTS.POINTS: [[5 * 32, 9 * 32], [32 + 5 * 32, 9 * 32],
[32 + 5 * 32, 32 + 9 * 32],
[5 * 32, 32 + 9 * 32]], },
{V1ELEMENTS.GID: "096",
V1ELEMENTS.POINTS: [[6 * 32, 9 * 32], [32 + 6 * 32, 9 * 32],
[32 + 6 * 32, 32 + 9 * 32],
[6 * 32, 32 + 9 * 32]], },
{V1ELEMENTS.GID: "097",
V1ELEMENTS.POINTS: [[7 * 32, 9 * 32], [32 + 7 * 32, 9 * 32],
[32 + 7 * 32, 32 + 9 * 32],
[7 * 32, 32 + 9 * 32]], },
{V1ELEMENTS.GID: "098",
V1ELEMENTS.POINTS: [[8 * 32, 9 * 32], [32 + 8 * 32, 9 * 32],
[32 + 8 * 32, 32 + 9 * 32],
[8 * 32, 32 + 9 * 32]], },
{V1ELEMENTS.GID: "099",
V1ELEMENTS.POINTS: [[9 * 32, 9 * 32], [32 + 9 * 32, 9 * 32],
[32 + 9 * 32, 32 + 9 * 32],
[9 * 32, 32 + 9 * 32]], },
]}
SDEF_GRID_10X10_SPACE_50 = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "out.png.sdef",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0 * 82, 0 * 82], [32 + 0 * 82, 0 * 82],
[32 + 0 * 82, 32 + 0 * 82],
[0 * 82, 32 + 0 * 82]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[1 * 82, 0 * 82], [32 + 1 * 82, 0 * 82],
[32 + 1 * 82, 32 + 0 * 82],
[1 * 82, 32 + 0 * 82]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[2 * 82, 0 * 82], [32 + 2 * 82, 0 * 82],
[32 + 2 * 82, 32 + 0 * 82],
[2 * 82, 32 + 0 * 82]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[3 * 82, 0 * 82], [32 + 3 * 82, 0 * 82],
[32 + 3 * 82, 32 + 0 * 82],
[3 * 82, 32 + 0 * 82]], },
{V1ELEMENTS.GID: "004",
V1ELEMENTS.POINTS: [[4 * 82, 0 * 82], [32 + 4 * 82, 0 * 82],
[32 + 4 * 82, 32 + 0 * 82],
[4 * 82, 32 + 0 * 82]], },
{V1ELEMENTS.GID: "005",
V1ELEMENTS.POINTS: [[5 * 82, 0 * 82], [32 + 5 * 82, 0 * 82],
[32 + 5 * 82, 32 + 0 * 82],
[5 * 82, 32 + 0 * 82]], },
{V1ELEMENTS.GID: "006",
V1ELEMENTS.POINTS: [[6 * 82, 0 * 82], [32 + 6 * 82, 0 * 82],
[32 + 6 * 82, 32 + 0 * 82],
[6 * 82, 32 + 0 * 82]], },
{V1ELEMENTS.GID: "007",
V1ELEMENTS.POINTS: [[7 * 82, 0 * 82], [32 + 7 * 82, 0 * 82],
[32 + 7 * 82, 32 + 0 * 82],
[7 * 82, 32 + 0 * 82]], },
{V1ELEMENTS.GID: "008",
V1ELEMENTS.POINTS: [[8 * 82, 0 * 82], [32 + 8 * 82, 0 * 82],
[32 + 8 * 82, 32 + 0 * 82],
[8 * 82, 32 + 0 * 82]], },
{V1ELEMENTS.GID: "009",
V1ELEMENTS.POINTS: [[9 * 82, 0 * 82], [32 + 9 * 82, 0 * 82],
[32 + 9 * 82, 32 + 0 * 82],
[9 * 82, 32 + 0 * 82]], },
{V1ELEMENTS.GID: "010",
V1ELEMENTS.POINTS: [[0 * 82, 1 * 82], [32 + 0 * 82, 1 * 82],
[32 + 0 * 82, 32 + 1 * 82],
[0 * 82, 32 + 1 * 82]], },
{V1ELEMENTS.GID: "011",
V1ELEMENTS.POINTS: [[1 * 82, 1 * 82], [32 + 1 * 82, 1 * 82],
[32 + 1 * 82, 32 + 1 * 82],
[1 * 82, 32 + 1 * 82]], },
{V1ELEMENTS.GID: "012",
V1ELEMENTS.POINTS: [[2 * 82, 1 * 82], [32 + 2 * 82, 1 * 82],
[32 + 2 * 82, 32 + 1 * 82],
[2 * 82, 32 + 1 * 82]], },
{V1ELEMENTS.GID: "013",
V1ELEMENTS.POINTS: [[3 * 82, 1 * 82], [32 + 3 * 82, 1 * 82],
[32 + 3 * 82, 32 + 1 * 82],
[3 * 82, 32 + 1 * 82]], },
{V1ELEMENTS.GID: "014",
V1ELEMENTS.POINTS: [[4 * 82, 1 * 82], [32 + 4 * 82, 1 * 82],
[32 + 4 * 82, 32 + 1 * 82],
[4 * 82, 32 + 1 * 82]], },
{V1ELEMENTS.GID: "015",
V1ELEMENTS.POINTS: [[5 * 82, 1 * 82], [32 + 5 * 82, 1 * 82],
[32 + 5 * 82, 32 + 1 * 82],
[5 * 82, 32 + 1 * 82]], },
{V1ELEMENTS.GID: "016",
V1ELEMENTS.POINTS: [[6 * 82, 1 * 82], [32 + 6 * 82, 1 * 82],
[32 + 6 * 82, 32 + 1 * 82],
[6 * 82, 32 + 1 * 82]], },
{V1ELEMENTS.GID: "017",
V1ELEMENTS.POINTS: [[7 * 82, 1 * 82], [32 + 7 * 82, 1 * 82],
[32 + 7 * 82, 32 + 1 * 82],
[7 * 82, 32 + 1 * 82]], },
{V1ELEMENTS.GID: "018",
V1ELEMENTS.POINTS: [[8 * 82, 1 * 82], [32 + 8 * 82, 1 * 82],
[32 + 8 * 82, 32 + 1 * 82],
[8 * 82, 32 + 1 * 82]], },
{V1ELEMENTS.GID: "019",
V1ELEMENTS.POINTS: [[9 * 82, 1 * 82], [32 + 9 * 82, 1 * 82],
[32 + 9 * 82, 32 + 1 * 82],
[9 * 82, 32 + 1 * 82]], },
{V1ELEMENTS.GID: "020",
V1ELEMENTS.POINTS: [[0 * 82, 2 * 82], [32 + 0 * 82, 2 * 82],
[32 + 0 * 82, 32 + 2 * 82],
[0 * 82, 32 + 2 * 82]], },
{V1ELEMENTS.GID: "021",
V1ELEMENTS.POINTS: [[1 * 82, 2 * 82], [32 + 1 * 82, 2 * 82],
[32 + 1 * 82, 32 + 2 * 82],
[1 * 82, 32 + 2 * 82]], },
{V1ELEMENTS.GID: "022",
V1ELEMENTS.POINTS: [[2 * 82, 2 * 82], [32 + 2 * 82, 2 * 82],
[32 + 2 * 82, 32 + 2 * 82],
[2 * 82, 32 + 2 * 82]], },
{V1ELEMENTS.GID: "023",
V1ELEMENTS.POINTS: [[3 * 82, 2 * 82], [32 + 3 * 82, 2 * 82],
[32 + 3 * 82, 32 + 2 * 82],
[3 * 82, 32 + 2 * 82]], },
{V1ELEMENTS.GID: "024",
V1ELEMENTS.POINTS: [[4 * 82, 2 * 82], [32 + 4 * 82, 2 * 82],
[32 + 4 * 82, 32 + 2 * 82],
[4 * 82, 32 + 2 * 82]], },
{V1ELEMENTS.GID: "025",
V1ELEMENTS.POINTS: [[5 * 82, 2 * 82], [32 + 5 * 82, 2 * 82],
[32 + 5 * 82, 32 + 2 * 82],
[5 * 82, 32 + 2 * 82]], },
{V1ELEMENTS.GID: "026",
V1ELEMENTS.POINTS: [[6 * 82, 2 * 82], [32 + 6 * 82, 2 * 82],
[32 + 6 * 82, 32 + 2 * 82],
[6 * 82, 32 + 2 * 82]], },
{V1ELEMENTS.GID: "027",
V1ELEMENTS.POINTS: [[7 * 82, 2 * 82], [32 + 7 * 82, 2 * 82],
[32 + 7 * 82, 32 + 2 * 82],
[7 * 82, 32 + 2 * 82]], },
{V1ELEMENTS.GID: "028",
V1ELEMENTS.POINTS: [[8 * 82, 2 * 82], [32 + 8 * 82, 2 * 82],
[32 + 8 * 82, 32 + 2 * 82],
[8 * 82, 32 + 2 * 82]], },
{V1ELEMENTS.GID: "029",
V1ELEMENTS.POINTS: [[9 * 82, 2 * 82], [32 + 9 * 82, 2 * 82],
[32 + 9 * 82, 32 + 2 * 82],
[9 * 82, 32 + 2 * 82]], },
{V1ELEMENTS.GID: "030",
V1ELEMENTS.POINTS: [[0 * 82, 3 * 82], [32 + 0 * 82, 3 * 82],
[32 + 0 * 82, 32 + 3 * 82],
[0 * 82, 32 + 3 * 82]], },
{V1ELEMENTS.GID: "031",
V1ELEMENTS.POINTS: [[1 * 82, 3 * 82], [32 + 1 * 82, 3 * 82],
[32 + 1 * 82, 32 + 3 * 82],
[1 * 82, 32 + 3 * 82]], },
{V1ELEMENTS.GID: "032",
V1ELEMENTS.POINTS: [[2 * 82, 3 * 82], [32 + 2 * 82, 3 * 82],
[32 + 2 * 82, 32 + 3 * 82],
[2 * 82, 32 + 3 * 82]], },
{V1ELEMENTS.GID: "033",
V1ELEMENTS.POINTS: [[3 * 82, 3 * 82], [32 + 3 * 82, 3 * 82],
[32 + 3 * 82, 32 + 3 * 82],
[3 * 82, 32 + 3 * 82]], },
{V1ELEMENTS.GID: "034",
V1ELEMENTS.POINTS: [[4 * 82, 3 * 82], [32 + 4 * 82, 3 * 82],
[32 + 4 * 82, 32 + 3 * 82],
[4 * 82, 32 + 3 * 82]], },
{V1ELEMENTS.GID: "035",
V1ELEMENTS.POINTS: [[5 * 82, 3 * 82], [32 + 5 * 82, 3 * 82],
[32 + 5 * 82, 32 + 3 * 82],
[5 * 82, 32 + 3 * 82]], },
{V1ELEMENTS.GID: "036",
V1ELEMENTS.POINTS: [[6 * 82, 3 * 82], [32 + 6 * 82, 3 * 82],
[32 + 6 * 82, 32 + 3 * 82],
[6 * 82, 32 + 3 * 82]], },
{V1ELEMENTS.GID: "037",
V1ELEMENTS.POINTS: [[7 * 82, 3 * 82], [32 + 7 * 82, 3 * 82],
[32 + 7 * 82, 32 + 3 * 82],
[7 * 82, 32 + 3 * 82]], },
{V1ELEMENTS.GID: "038",
V1ELEMENTS.POINTS: [[8 * 82, 3 * 82], [32 + 8 * 82, 3 * 82],
[32 + 8 * 82, 32 + 3 * 82],
[8 * 82, 32 + 3 * 82]], },
{V1ELEMENTS.GID: "039",
V1ELEMENTS.POINTS: [[9 * 82, 3 * 82], [32 + 9 * 82, 3 * 82],
[32 + 9 * 82, 32 + 3 * 82],
[9 * 82, 32 + 3 * 82]], },
{V1ELEMENTS.GID: "040",
V1ELEMENTS.POINTS: [[0 * 82, 4 * 82], [32 + 0 * 82, 4 * 82],
[32 + 0 * 82, 32 + 4 * 82],
[0 * 82, 32 + 4 * 82]], },
{V1ELEMENTS.GID: "041",
V1ELEMENTS.POINTS: [[1 * 82, 4 * 82], [32 + 1 * 82, 4 * 82],
[32 + 1 * 82, 32 + 4 * 82],
[1 * 82, 32 + 4 * 82]], },
{V1ELEMENTS.GID: "042",
V1ELEMENTS.POINTS: [[2 * 82, 4 * 82], [32 + 2 * 82, 4 * 82],
[32 + 2 * 82, 32 + 4 * 82],
[2 * 82, 32 + 4 * 82]], },
{V1ELEMENTS.GID: "043",
V1ELEMENTS.POINTS: [[3 * 82, 4 * 82], [32 + 3 * 82, 4 * 82],
[32 + 3 * 82, 32 + 4 * 82],
[3 * 82, 32 + 4 * 82]], },
{V1ELEMENTS.GID: "044",
V1ELEMENTS.POINTS: [[4 * 82, 4 * 82], [32 + 4 * 82, 4 * 82],
[32 + 4 * 82, 32 + 4 * 82],
[4 * 82, 32 + 4 * 82]], },
{V1ELEMENTS.GID: "045",
V1ELEMENTS.POINTS: [[5 * 82, 4 * 82], [32 + 5 * 82, 4 * 82],
[32 + 5 * 82, 32 + 4 * 82],
[5 * 82, 32 + 4 * 82]], },
{V1ELEMENTS.GID: "046",
V1ELEMENTS.POINTS: [[6 * 82, 4 * 82], [32 + 6 * 82, 4 * 82],
[32 + 6 * 82, 32 + 4 * 82],
[6 * 82, 32 + 4 * 82]], },
{V1ELEMENTS.GID: "047",
V1ELEMENTS.POINTS: [[7 * 82, 4 * 82], [32 + 7 * 82, 4 * 82],
[32 + 7 * 82, 32 + 4 * 82],
[7 * 82, 32 + 4 * 82]], },
{V1ELEMENTS.GID: "048",
V1ELEMENTS.POINTS: [[8 * 82, 4 * 82], [32 + 8 * 82, 4 * 82],
[32 + 8 * 82, 32 + 4 * 82],
[8 * 82, 32 + 4 * 82]], },
{V1ELEMENTS.GID: "049",
V1ELEMENTS.POINTS: [[9 * 82, 4 * 82], [32 + 9 * 82, 4 * 82],
[32 + 9 * 82, 32 + 4 * 82],
[9 * 82, 32 + 4 * 82]], },
{V1ELEMENTS.GID: "050",
V1ELEMENTS.POINTS: [[0 * 82, 5 * 82], [32 + 0 * 82, 5 * 82],
[32 + 0 * 82, 32 + 5 * 82],
[0 * 82, 32 + 5 * 82]], },
{V1ELEMENTS.GID: "051",
V1ELEMENTS.POINTS: [[1 * 82, 5 * 82], [32 + 1 * 82, 5 * 82],
[32 + 1 * 82, 32 + 5 * 82],
[1 * 82, 32 + 5 * 82]], },
{V1ELEMENTS.GID: "052",
V1ELEMENTS.POINTS: [[2 * 82, 5 * 82], [32 + 2 * 82, 5 * 82],
[32 + 2 * 82, 32 + 5 * 82],
[2 * 82, 32 + 5 * 82]], },
{V1ELEMENTS.GID: "053",
V1ELEMENTS.POINTS: [[3 * 82, 5 * 82], [32 + 3 * 82, 5 * 82],
[32 + 3 * 82, 32 + 5 * 82],
[3 * 82, 32 + 5 * 82]], },
{V1ELEMENTS.GID: "054",
V1ELEMENTS.POINTS: [[4 * 82, 5 * 82], [32 + 4 * 82, 5 * 82],
[32 + 4 * 82, 32 + 5 * 82],
[4 * 82, 32 + 5 * 82]], },
{V1ELEMENTS.GID: "055",
V1ELEMENTS.POINTS: [[5 * 82, 5 * 82], [32 + 5 * 82, 5 * 82],
[32 + 5 * 82, 32 + 5 * 82],
[5 * 82, 32 + 5 * 82]], },
{V1ELEMENTS.GID: "056",
V1ELEMENTS.POINTS: [[6 * 82, 5 * 82], [32 + 6 * 82, 5 * 82],
[32 + 6 * 82, 32 + 5 * 82],
[6 * 82, 32 + 5 * 82]], },
{V1ELEMENTS.GID: "057",
V1ELEMENTS.POINTS: [[7 * 82, 5 * 82], [32 + 7 * 82, 5 * 82],
[32 + 7 * 82, 32 + 5 * 82],
[7 * 82, 32 + 5 * 82]], },
{V1ELEMENTS.GID: "058",
V1ELEMENTS.POINTS: [[8 * 82, 5 * 82], [32 + 8 * 82, 5 * 82],
[32 + 8 * 82, 32 + 5 * 82],
[8 * 82, 32 + 5 * 82]], },
{V1ELEMENTS.GID: "059",
V1ELEMENTS.POINTS: [[9 * 82, 5 * 82], [32 + 9 * 82, 5 * 82],
[32 + 9 * 82, 32 + 5 * 82],
[9 * 82, 32 + 5 * 82]], },
{V1ELEMENTS.GID: "060",
V1ELEMENTS.POINTS: [[0 * 82, 6 * 82], [32 + 0 * 82, 6 * 82],
[32 + 0 * 82, 32 + 6 * 82],
[0 * 82, 32 + 6 * 82]], },
{V1ELEMENTS.GID: "061",
V1ELEMENTS.POINTS: [[1 * 82, 6 * 82], [32 + 1 * 82, 6 * 82],
[32 + 1 * 82, 32 + 6 * 82],
[1 * 82, 32 + 6 * 82]], },
{V1ELEMENTS.GID: "062",
V1ELEMENTS.POINTS: [[2 * 82, 6 * 82], [32 + 2 * 82, 6 * 82],
[32 + 2 * 82, 32 + 6 * 82],
[2 * 82, 32 + 6 * 82]], },
{V1ELEMENTS.GID: "063",
V1ELEMENTS.POINTS: [[3 * 82, 6 * 82], [32 + 3 * 82, 6 * 82],
[32 + 3 * 82, 32 + 6 * 82],
[3 * 82, 32 + 6 * 82]], },
{V1ELEMENTS.GID: "064",
V1ELEMENTS.POINTS: [[4 * 82, 6 * 82], [32 + 4 * 82, 6 * 82],
[32 + 4 * 82, 32 + 6 * 82],
[4 * 82, 32 + 6 * 82]], },
{V1ELEMENTS.GID: "065",
V1ELEMENTS.POINTS: [[5 * 82, 6 * 82], [32 + 5 * 82, 6 * 82],
[32 + 5 * 82, 32 + 6 * 82],
[5 * 82, 32 + 6 * 82]], },
{V1ELEMENTS.GID: "066",
V1ELEMENTS.POINTS: [[6 * 82, 6 * 82], [32 + 6 * 82, 6 * 82],
[32 + 6 * 82, 32 + 6 * 82],
[6 * 82, 32 + 6 * 82]], },
{V1ELEMENTS.GID: "067",
V1ELEMENTS.POINTS: [[7 * 82, 6 * 82], [32 + 7 * 82, 6 * 82],
[32 + 7 * 82, 32 + 6 * 82],
[7 * 82, 32 + 6 * 82]], },
{V1ELEMENTS.GID: "068",
V1ELEMENTS.POINTS: [[8 * 82, 6 * 82], [32 + 8 * 82, 6 * 82],
[32 + 8 * 82, 32 + 6 * 82],
[8 * 82, 32 + 6 * 82]], },
{V1ELEMENTS.GID: "069",
V1ELEMENTS.POINTS: [[9 * 82, 6 * 82], [32 + 9 * 82, 6 * 82],
[32 + 9 * 82, 32 + 6 * 82],
[9 * 82, 32 + 6 * 82]], },
{V1ELEMENTS.GID: "070",
V1ELEMENTS.POINTS: [[0 * 82, 7 * 82], [32 + 0 * 82, 7 * 82],
[32 + 0 * 82, 32 + 7 * 82],
[0 * 82, 32 + 7 * 82]], },
{V1ELEMENTS.GID: "071",
V1ELEMENTS.POINTS: [[1 * 82, 7 * 82], [32 + 1 * 82, 7 * 82],
[32 + 1 * 82, 32 + 7 * 82],
[1 * 82, 32 + 7 * 82]], },
{V1ELEMENTS.GID: "072",
V1ELEMENTS.POINTS: [[2 * 82, 7 * 82], [32 + 2 * 82, 7 * 82],
[32 + 2 * 82, 32 + 7 * 82],
[2 * 82, 32 + 7 * 82]], },
{V1ELEMENTS.GID: "073",
V1ELEMENTS.POINTS: [[3 * 82, 7 * 82], [32 + 3 * 82, 7 * 82],
[32 + 3 * 82, 32 + 7 * 82],
[3 * 82, 32 + 7 * 82]], },
{V1ELEMENTS.GID: "074",
V1ELEMENTS.POINTS: [[4 * 82, 7 * 82], [32 + 4 * 82, 7 * 82],
[32 + 4 * 82, 32 + 7 * 82],
[4 * 82, 32 + 7 * 82]], },
{V1ELEMENTS.GID: "075",
V1ELEMENTS.POINTS: [[5 * 82, 7 * 82], [32 + 5 * 82, 7 * 82],
[32 + 5 * 82, 32 + 7 * 82],
[5 * 82, 32 + 7 * 82]], },
{V1ELEMENTS.GID: "076",
V1ELEMENTS.POINTS: [[6 * 82, 7 * 82], [32 + 6 * 82, 7 * 82],
[32 + 6 * 82, 32 + 7 * 82],
[6 * 82, 32 + 7 * 82]], },
{V1ELEMENTS.GID: "077",
V1ELEMENTS.POINTS: [[7 * 82, 7 * 82], [32 + 7 * 82, 7 * 82],
[32 + 7 * 82, 32 + 7 * 82],
[7 * 82, 32 + 7 * 82]], },
{V1ELEMENTS.GID: "078",
V1ELEMENTS.POINTS: [[8 * 82, 7 * 82], [32 + 8 * 82, 7 * 82],
[32 + 8 * 82, 32 + 7 * 82],
[8 * 82, 32 + 7 * 82]], },
{V1ELEMENTS.GID: "079",
V1ELEMENTS.POINTS: [[9 * 82, 7 * 82], [32 + 9 * 82, 7 * 82],
[32 + 9 * 82, 32 + 7 * 82],
[9 * 82, 32 + 7 * 82]], },
{V1ELEMENTS.GID: "080",
V1ELEMENTS.POINTS: [[0 * 82, 8 * 82], [32 + 0 * 82, 8 * 82],
[32 + 0 * 82, 32 + 8 * 82],
[0 * 82, 32 + 8 * 82]], },
{V1ELEMENTS.GID: "081",
V1ELEMENTS.POINTS: [[1 * 82, 8 * 82], [32 + 1 * 82, 8 * 82],
[32 + 1 * 82, 32 + 8 * 82],
[1 * 82, 32 + 8 * 82]], },
{V1ELEMENTS.GID: "082",
V1ELEMENTS.POINTS: [[2 * 82, 8 * 82], [32 + 2 * 82, 8 * 82],
[32 + 2 * 82, 32 + 8 * 82],
[2 * 82, 32 + 8 * 82]], },
{V1ELEMENTS.GID: "083",
V1ELEMENTS.POINTS: [[3 * 82, 8 * 82], [32 + 3 * 82, 8 * 82],
[32 + 3 * 82, 32 + 8 * 82],
[3 * 82, 32 + 8 * 82]], },
{V1ELEMENTS.GID: "084",
V1ELEMENTS.POINTS: [[4 * 82, 8 * 82], [32 + 4 * 82, 8 * 82],
[32 + 4 * 82, 32 + 8 * 82],
[4 * 82, 32 + 8 * 82]], },
{V1ELEMENTS.GID: "085",
V1ELEMENTS.POINTS: [[5 * 82, 8 * 82], [32 + 5 * 82, 8 * 82],
[32 + 5 * 82, 32 + 8 * 82],
[5 * 82, 32 + 8 * 82]], },
{V1ELEMENTS.GID: "086",
V1ELEMENTS.POINTS: [[6 * 82, 8 * 82], [32 + 6 * 82, 8 * 82],
[32 + 6 * 82, 32 + 8 * 82],
[6 * 82, 32 + 8 * 82]], },
{V1ELEMENTS.GID: "087",
V1ELEMENTS.POINTS: [[7 * 82, 8 * 82], [32 + 7 * 82, 8 * 82],
[32 + 7 * 82, 32 + 8 * 82],
[7 * 82, 32 + 8 * 82]], },
{V1ELEMENTS.GID: "088",
V1ELEMENTS.POINTS: [[8 * 82, 8 * 82], [32 + 8 * 82, 8 * 82],
[32 + 8 * 82, 32 + 8 * 82],
[8 * 82, 32 + 8 * 82]], },
{V1ELEMENTS.GID: "089",
V1ELEMENTS.POINTS: [[9 * 82, 8 * 82], [32 + 9 * 82, 8 * 82],
[32 + 9 * 82, 32 + 8 * 82],
[9 * 82, 32 + 8 * 82]], },
{V1ELEMENTS.GID: "090",
V1ELEMENTS.POINTS: [[0 * 82, 9 * 82], [32 + 0 * 82, 9 * 82],
[32 + 0 * 82, 32 + 9 * 82],
[0 * 82, 32 + 9 * 82]], },
{V1ELEMENTS.GID: "091",
V1ELEMENTS.POINTS: [[1 * 82, 9 * 82], [32 + 1 * 82, 9 * 82],
[32 + 1 * 82, 32 + 9 * 82],
[1 * 82, 32 + 9 * 82]], },
{V1ELEMENTS.GID: "092",
V1ELEMENTS.POINTS: [[2 * 82, 9 * 82], [32 + 2 * 82, 9 * 82],
[32 + 2 * 82, 32 + 9 * 82],
[2 * 82, 32 + 9 * 82]], },
{V1ELEMENTS.GID: "093",
V1ELEMENTS.POINTS: [[3 * 82, 9 * 82], [32 + 3 * 82, 9 * 82],
[32 + 3 * 82, 32 + 9 * 82],
[3 * 82, 32 + 9 * 82]], },
{V1ELEMENTS.GID: "094",
V1ELEMENTS.POINTS: [[4 * 82, 9 * 82], [32 + 4 * 82, 9 * 82],
[32 + 4 * 82, 32 + 9 * 82],
[4 * 82, 32 + 9 * 82]], },
{V1ELEMENTS.GID: "095",
V1ELEMENTS.POINTS: [[5 * 82, 9 * 82], [32 + 5 * 82, 9 * 82],
[32 + 5 * 82, 32 + 9 * 82],
[5 * 82, 32 + 9 * 82]], },
{V1ELEMENTS.GID: "096",
V1ELEMENTS.POINTS: [[6 * 82, 9 * 82], [32 + 6 * 82, 9 * 82],
[32 + 6 * 82, 32 + 9 * 82],
[6 * 82, 32 + 9 * 82]], },
{V1ELEMENTS.GID: "097",
V1ELEMENTS.POINTS: [[7 * 82, 9 * 82], [32 + 7 * 82, 9 * 82],
[32 + 7 * 82, 32 + 9 * 82],
[7 * 82, 32 + 9 * 82]], },
{V1ELEMENTS.GID: "098",
V1ELEMENTS.POINTS: [[8 * 82, 9 * 82], [32 + 8 * 82, 9 * 82],
[32 + 8 * 82, 32 + 9 * 82],
[8 * 82, 32 + 9 * 82]], },
{V1ELEMENTS.GID: "099",
V1ELEMENTS.POINTS: [[9 * 82, 9 * 82], [32 + 9 * 82, 9 * 82],
[32 + 9 * 82, 32 + 9 * 82],
[9 * 82, 32 + 9 * 82]], },
]}
SDEF_OVERLAPPING_SPRITES = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [0, 32]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[32, 0], [64, 0], [32, 32],
[28, 16]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[0, 32], [28, 28], [36, 64],
[0, 64]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[32, 32], [64, 38], [64, 64],
[48, 48]], },
]}
SDEF_OVERLAPPING_SPACING0 = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [0, 32]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[36, 0], [68, 0], [36, 32],
[32, 16]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[0, 36], [28, 32], [36, 68],
[0, 68]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[36, 32], [68, 38], [68, 64],
[52, 48]], },
]}
SDEF_OVERLAPPING_SPACING3 = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [0, 32]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[39, 0], [71, 0], [39, 32],
[35, 16]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[0, 39], [28, 35], [36, 71],
[0, 71]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[39, 35], [71, 41], [71, 67],
[55, 51]], },
]}
SDEF_EXTREME_OVERLAPPING = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5], [0, 5]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[5, 0], [64, 0], [64, 10], [5, 10]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[10, 3], [40, 3], [40, 15],
[10, 15]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[64, 0], [71, 0], [71, 67],
[64, 67]], },
]}
SDEF_EXTREME_OVERLAPPING_MARGIN10 = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[10, 10], [42, 10], [42, 15],
[10, 15]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[5 + 10, 0 + 10],
[64 + 10, 0 + 10],
[64 + 10, 10 + 10],
[5 + 10, 10 + 10]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[10 + 10, 3 + 10],
[40 + 10, 3 + 10],
[40 + 10, 15 + 10],
[10 + 10, 15 + 10]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[64 + 10, 0 + 10],
[71 + 10, 0 + 10],
[71 + 10, 67 + 10],
[64 + 10, 67 + 10]], },
]}
SDEF_EXTREME_OVERLAPPING_SPACING5 = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5],
[0, 5]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[5 + 32, 0], [64 + 32, 0],
[64 + 32, 10],
[5 + 32, 10]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[10 + 30, 3 + 12],
[40 + 30, 3 + 12],
[40 + 30, 15 + 12],
[10 + 30, 15 + 12]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[64 + 37, 0], [71 + 37, 0],
[71 + 37, 67],
[64 + 37, 67]], },
]}
SDEF_INVALID_DUPLICATE_NAMES = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5],
[0, 5]], },
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[37, 0], [96, 0], [96, 10],
[37, 10]], },
]}
SDEF_INVALID_MISSING_SPRITES = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png", }
SDEF_INVALID_MISSING_SPRITES_LIST_EMPTY = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: []}
SDEF_INVALID_INCONSISTENT_ORIENTATION = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[136, 0], [143, 10],
[143, 67], [136, 67]], },
{V1ELEMENTS.GID: "002",
V1ELEMENTS.POINTS: [[136, 67], [143, 67],
[143, 10], [136, 0]], },
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[136, 0], [143, 10],
[143, 67], [136, 67]], },
]}
SDEF_INVALID_NEGATIVE_Y_COORDINATES = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[136, 0], [143, -10],
[143, 67], [136, 67]], },
]}
SDEF_INVALID_NEGATIVE_X_COORDINATES = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "003",
V1ELEMENTS.POINTS: [[136, 0], [143, 10],
[-143, 67], [136, 67]], },
]}
SDEF_INVALID_VERSION = {V1ELEMENTS.VERSION: "0.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5], [0, 5]], },
]}
SDEF_INVALID_MISSING_VERSION = {V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5],
[0, 5]], },
]}
SDEF_INVALID_MISSING_SPRITE_NAME = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5],
[0, 5]], },
{V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5],
[0, 5]], },
]}
SDEF_INVALID_MISSING_POINTS = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5], [0, 5]], },
{V1ELEMENTS.GID: "001", },
]}
SDEF_INVALID_MISSING_POINT_COORDINATES = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5],
[0, 5]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[32, 5], [0, 5]], },
]}
SDEF_INVALID_MISSING_FILENAME = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5],
[0, 5]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[10, 10], [42, 10], [42, 15],
[10, 15]], },
]}
SDEF_INVALID_FILENAME_EMPTY = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[0, 0], [32, 0], [32, 5], [0, 5]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[10, 10], [42, 10], [42, 15],
[10, 15]], },
]}
SDEF_INVALID_COLINEAR_COORDINATES_TRIANGLE = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[10, 10], [5, 5],
[15, 15]], },
# colinear
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[32, 5], [0, 5],
[2, 3]], },
]}
SDEF_INVALID_COLINEAR_COORDINATES_POLYGON = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
# colinear points
V1ELEMENTS.POINTS: [[1, 1], [2, 2], [5, 5],
[10, 10], [55, 55],
[15, 15]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[32, 5], [0, 5],
[2, 3]], },
]}
SDEF_INVALID_COLINEAR_2_POINTS_SAME = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[32, 5], [32, 5], [0, 5]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[32, 5], [0, 5], [2, 3]], },
]}
SDEF_INVALID_COLINEAR_3_POINTS_SAME = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[5, 5], [5, 5], [5, 5]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[32, 5], [0, 5], [2, 3]], },
]}
SDEF_WARN_2_POINTS_SAME_IN_POLYGON = {V1ELEMENTS.VERSION: "1.0",
V1ELEMENTS.FILENAME: "x.png",
V1ELEMENTS.SPRITES: [
{V1ELEMENTS.GID: "000",
V1ELEMENTS.POINTS: [[32, 5], [0, 5], [0, 20],
[32, 5], [10, 6]], },
{V1ELEMENTS.GID: "001",
V1ELEMENTS.POINTS: [[32, 5], [0, 5], [2, 30]], },
]}
# noinspection PyUnusedLocal
[docs]class LoggerMock(object):
"""
The mock object for the logging
:param level: the logging level the mock should use, same as logging levels (e.g. logging.DEBUG)
"""
def __init__(self, level=logging.DEBUG):
self.messages = [] # [(level, msg), ]
self.level = level
[docs] def debug(self, msg, *args, **kwargs):
"""
The debug message to log.
:param msg: The message to log.
:param args: Arguments if msg is a format string.
:param kwargs: Keyword arguments.
"""
# logger.debug(msg, *args, **kwargs)
if self.level <= logging.DEBUG:
self.messages.append((logging.DEBUG, msg))
[docs] def info(self, msg, *args, **kwargs):
"""
The info message to log.
:param msg: The message to log.
:param args: Arguments if msg is a format string.
:param kwargs: Keyword arguments.
"""
# logger.info(msg, *args, **kwargs)
if self.level <= logging.INFO:
self.messages.append((logging.INFO, msg))
[docs] def error(self, msg, *args, **kwargs):
"""
The error message to log.
:param msg: The message to log.
:param args: Arguments if msg is a format string.
:param kwargs: Keyword arguments.
"""
# logger.error(msg, *args, **kwargs)
if self.level <= logging.ERROR:
self.messages.append((logging.ERROR, msg))
[docs] def warn(self, msg, *args, **kwargs):
"""
The warn message to log.
:param msg: The message to log.
:param args: Arguments if msg is a format string.
:param kwargs: Keyword arguments.
"""
# logger.warn(msg, *args, **kwargs)
if self.level <= logging.WARN:
self.messages.append((logging.WARN, msg))
[docs]class TestLoggerMock(unittest.TestCase):
[docs] def test_log_level_debug(self):
# arrange
logger_mock = LoggerMock()
# act
logger_mock.debug("debug")
logger_mock.info("info")
logger_mock.warn("warn")
logger_mock.error("error")
# verify
self.assertEqual(4, len(logger_mock.messages))
self.assertEqual((logging.DEBUG, "debug"), logger_mock.messages[0])
self.assertEqual((logging.INFO, "info"), logger_mock.messages[1])
self.assertEqual((logging.WARN, "warn"), logger_mock.messages[2])
self.assertEqual((logging.ERROR, "error"), logger_mock.messages[3])
[docs] def test_log_level_info(self):
# arrange
logger_mock = LoggerMock(level=logging.INFO)
# act
logger_mock.debug("debug")
logger_mock.info("info")
logger_mock.warn("warn")
logger_mock.error("error")
# verify
self.assertEqual(3, len(logger_mock.messages))
self.assertEqual((logging.INFO, "info"), logger_mock.messages[0])
self.assertEqual((logging.WARN, "warn"), logger_mock.messages[1])
self.assertEqual((logging.ERROR, "error"), logger_mock.messages[2])
[docs] def test_log_level_warn(self):
# arrange
logger_mock = LoggerMock(level=logging.WARN)
# act
logger_mock.debug("debug")
logger_mock.info("info")
logger_mock.warn("warn")
logger_mock.error("error")
# verify
self.assertEqual(2, len(logger_mock.messages))
self.assertEqual((logging.WARN, "warn"), logger_mock.messages[0])
self.assertEqual((logging.ERROR, "error"), logger_mock.messages[1])
[docs] def test_log_level_error(self):
# arrange
logger_mock = LoggerMock(level=logging.ERROR)
# act
logger_mock.debug("debug")
logger_mock.info("info")
logger_mock.warn("warn")
logger_mock.error("error")
# verify
self.assertEqual(1, len(logger_mock.messages))
self.assertEqual((logging.ERROR, "error"), logger_mock.messages[0])
[docs] def test_log_level_critical(self):
# arrange
logger_mock = LoggerMock(level=logging.CRITICAL)
# act
logger_mock.debug("debug")
logger_mock.info("info")
logger_mock.warn("warn")
logger_mock.error("error")
# verify
self.assertEqual(0, len(logger_mock.messages))
[docs]def get_method_names(obj):
"""
Generator function that returns the public method names of the given object (public methods mean none that
starts with '_').
:param obj: the object to get the method names from.
"""
import inspect
for m in inspect.getmembers(obj,
predicate=lambda x: inspect.ismethod(x) and not x.__name__.startswith('_') and type(
obj) == find_defining_class(obj, x.__name__)):
yield ((m[0], ), {})
[docs]def find_defining_class(obj, method_name):
"""
Finds the class where the method is defined.
:param obj: any object
:param method_name: the name of the method
:return: returns the type of first class defining the method, otherwise None
"""
type1 = type(obj)
type__mro = type1.mro()
for ty in type__mro:
dict__ = ty.__dict__
if method_name in dict__:
return ty
[docs]class TestFindDefiningClass(unittest.TestCase):
"""
This tests test the working of the function 'find_defining_class'.
"""
[docs] def test_find_defining_class(self):
# arrange
# noinspection PyDocstring
class Level0(object):
"""
The Level 0 class.
"""
def level0(self):
pass
def level01(self):
pass
def level02(self):
pass
def level012(self):
pass
# noinspection PyDocstring
class Level1(Level0):
"""
The level 1 class.
"""
def level1(self):
pass
def level01(self):
Level0.level01(self)
def level12(self):
pass
def level012(self):
Level0.level012(self)
# noinspection PyDocstring
class Level2(Level1):
"""
The level 2 class.
"""
def level2(self):
pass
def level12(self):
Level1.level12(self)
def level02(self):
Level1.level02(self)
def level012(self):
Level1.level012(self)
# act
level = Level2()
level.level0()
level.level01()
level.level02()
level.level012()
level.level1()
level.level12()
level.level2()
# verify
self.assertEqual(Level0, find_defining_class(level, "level0"))
self.assertEqual(Level1, find_defining_class(level, "level1"))
self.assertEqual(Level1, find_defining_class(level, "level01"))
self.assertEqual(Level2, find_defining_class(level, "level2"))
self.assertEqual(Level2, find_defining_class(level, "level02"))
self.assertEqual(Level2, find_defining_class(level, "level12"))
self.assertEqual(Level2, find_defining_class(level, "level012"))
[docs]class TestGridCommand(unittest.TestCase):
[docs] def setUp(self):
self.logger_mock = LoggerMock()
[docs] def test_simple_grid_generation(self):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
# act
actual_sprite_definition = sut.create_grid(2, 2, 32, 32, mut.FileInfo("out.png.sdef"))
# verify
self.maxDiff = None
data = sut.clone_sprite_definition(TestData.SDEF_GRID_2X2)
del data[V1ELEMENTS.SPRITES][0][V1ELEMENTS.ANCHOR]
self.assertDictEqual(data, actual_sprite_definition)
@ddtd.use_data_driven_testing_decorators
[docs]class TestSpriteDefinitionGeneration(unittest.TestCase):
[docs] def setUp(self):
self.logger_mock = LoggerMock()
@ddtd.test_case(TestData.SDEF_GRID_2X2, TestData.SDEF_GRID_2X2)
@ddtd.test_case(TestData.SDEF_OVERLAPPING_SPRITES, TestData.SDEF_OVERLAPPING_SPRITES, None,
test_name="overlapping_spacing_-1")
@ddtd.test_case(TestData.SDEF_OVERLAPPING_SPACING0, TestData.SDEF_OVERLAPPING_SPRITES, 0,
test_name="overlapping_spacing_0")
@ddtd.test_case(TestData.SDEF_OVERLAPPING_SPACING3, TestData.SDEF_OVERLAPPING_SPRITES, 3,
test_name="overlapping_spacing_3")
@ddtd.test_case(TestData.SDEF_EXTREME_OVERLAPPING_SPACING5, TestData.SDEF_EXTREME_OVERLAPPING, 5, 0,
test_name="overlapping_extreme_spacing_5")
@ddtd.test_case(TestData.SDEF_EXTREME_OVERLAPPING, TestData.SDEF_EXTREME_OVERLAPPING, None,
test_name="overlapping_extreme_no_spacing")
@ddtd.test_case(TestData.SDEF_EXTREME_OVERLAPPING_MARGIN10, TestData.SDEF_EXTREME_OVERLAPPING, None, 10,
test_name="overlapping_extreme_margin_10")
@ddtd.test_case(TestData.SDEF_GRID_10X10_SPACE_50, TestData.SDEF_GRID_10X10, 50, 0,
test_name="grid_10x10_spacing50")
def test_simple_grid_sprite_definition_generation(self, expected, sdef, spacing=None, margin=0):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
# act
actual_sprite_definition = sut.adjust_spacing(sdef, spacing)
actual_sprite_definition = sut.adjust_margin(actual_sprite_definition, margin)
# verify
self.maxDiff = None
self.assertDictEqual(expected, actual_sprite_definition)
[docs] def test_new_sprite_definition_is_a_different_instance(self):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
# act
actual = sut.adjust_spacing(TestData.SDEF_GRID_2X2, None)
# verify
self.assertFalse(actual is TestData.SDEF_GRID_2X2)
[docs] def test_margin_0(self):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
sdef = TestData.SDEF_GRID_2X2
margin = 0
# act
actual = sut.adjust_margin(sdef, margin)
# verify
self.assertDictEqual(TestData.SDEF_GRID_2X2, actual)
[docs] def test_margin_x(self):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
sdef = TestData.SDEF_GRID_2X2
margin = 33
# act
actual = sut.adjust_margin(sdef, margin)
# verify
self.maxDiff = None
self.assertDictEqual(TestData.SDEF_GRID_2X2_MARGIN_33, actual)
[docs] def test_special_aabb_margin_5(self):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
sdef = TestData.SDEF_GRID_2X2_SPECIAL_MARGIN
margin = 5
self.maxDiff = None
# act
actual = sut.adjust_margin(sdef, margin)
# verify
self.assertDictEqual(TestData.SDEF_GRID_2X2_SPECIAL_MARGIN_5, actual)
[docs] def test_negative_margin_raises_ValueError(self):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
sdef = TestData.SDEF_GRID_2X2_SPECIAL_MARGIN
margin = -5
self.maxDiff = None
# act / verify
self.assertRaises(ValueError, sut.adjust_margin, sdef, margin)
[docs]class TestImageGeneration(unittest.TestCase):
[docs] def setUp(self):
self.logger_mock = LoggerMock()
[docs] def test_image_is_created(self):
# arrange
import pygame
sut = mut.SpritesheetLib10(self.logger_mock)
# act
actual = sut.create_image(TestData.SDEF_GRID_2X2)
actual_size = actual.get_size()
# verify
self.assertIsInstance(actual, pygame.Surface)
expected_size = (64, 64)
self.assertEqual(expected_size, actual_size)
[docs] def test_image_with_margin_is_created(self):
# arrange
import pygame
sut = mut.SpritesheetLib10(self.logger_mock)
margin = 20
sdef_grid_2x2_with_margin = sut.adjust_margin(TestData.SDEF_GRID_2X2, margin)
# act
actual = sut.create_image(sdef_grid_2x2_with_margin)
actual_size = actual.get_size()
# verify
self.assertIsInstance(actual, pygame.Surface)
expected_size = (104, 104)
self.assertEqual(expected_size, actual_size)
@ddtd.use_data_driven_testing_decorators
[docs]class TestAABB(unittest.TestCase):
[docs] def setUp(self):
self.min_x = 2
self.max_x = 20
self.min_y = 5
self.max_y = 7
self.center_x = self.min_x + (self.max_x - self.min_x) // 2
self.center_y = self.min_y + (self.max_y - self.min_y) // 2
[docs] def test_aabb_min_max(self):
# arrange
# act
aabb = mut.AABB(self.min_x, self.min_y, self.max_x, self.max_y)
# verify
self.assertEqual(self.min_x, aabb.min_x)
self.assertEqual(self.min_y, aabb.min_y)
self.assertEqual(self.max_x, aabb.max_x)
self.assertEqual(self.max_y, aabb.max_y)
self.assertEqual(self.center_x, aabb.center_x)
self.assertEqual(self.center_y, aabb.center_y)
[docs] def test_aabb_wrong_value_order_x(self):
# arrange
# act / verify
self.assertRaises(AssertionError, mut.AABB, self.max_x, self.min_y, self.min_x, self.max_y)
[docs] def test_aabb_wrong_value_order_y(self):
# arrange
# act / verify
self.assertRaises(AssertionError, mut.AABB, self.min_x, self.max_y, self.max_x, self.min_y)
@ddtd.test_case(11, 11, 20, 20, True)
@ddtd.test_case(1, 1, 9, 9, True)
@ddtd.test_case(1, 11, 9, 20, True)
@ddtd.test_case(11, 1, 20, 9, True)
@ddtd.test_case(2, 6, 20, 9, True)
@ddtd.test_case(6, 2, 9, 20, True)
@ddtd.test_case(6, 2, 9, 10, True)
@ddtd.test_case(2, 6, 10, 9, True)
@ddtd.test_case(12, 6, 19, 9, True)
@ddtd.test_case(6, 12, 9, 19, True)
@ddtd.test_case(1, 1, 3, 3, False)
@ddtd.test_case(19, 10, 30, 13, False)
@ddtd.test_case(1, 10, 3, 13, False)
@ddtd.test_case(7, 19, 9, 33, False)
def test_aabb_collision(self, v, w, x, y, expected):
# arrange
other = mut.AABB(v, w, x, y)
aabb = mut.AABB(5, 5, 15, 15)
# act
actual = aabb.collide(other)
other_actual = other.collide(aabb)
# verify
self.assertEqual(expected, actual)
self.assertEqual(other_actual, actual)
[docs] def test_aabb_from_points(self):
# arrange
points = [(2, 3), (45, 2), (15, 33)]
# act
actual = mut.AABB.from_points(points)
# verify
expected = mut.AABB(2, 2, 45, 33)
self.assertEqual(expected, actual)
[docs] def test_aabb_are_not_equal(self):
# arrange
aabb = mut.AABB(1, 1, 2, 2)
other = mut.AABB(1, 2, 3, 4)
# act
actual = aabb != other
# verify
self.assertEqual(True, actual)
[docs] def test_aabb_not_equal_to_other_type(self):
# arrange
aabb = mut.AABB(1, 1, 5, 5)
other = object()
# act
actual = aabb != other
# verify
self.assertEqual(True, actual)
[docs] def test_aabb_equal_to_other_type(self):
# arrange
aabb = mut.AABB(1, 1, 5, 5)
other = object()
# act
actual = aabb == other
# verify
self.assertEqual(False, actual)
[docs] def test_aabb_are_not_equal_false(self):
# arrange
aabb = mut.AABB(1, 2, 3, 4)
other = mut.AABB(10, 20, 30, 40)
# act
actual = aabb == other
# verify
self.assertEqual(False, actual)
[docs] def test_aabb_are_equal(self):
# arrange
aabb = mut.AABB(1, 2, 3, 4)
other = mut.AABB(1, 2, 3, 4)
# act
actual = aabb == other
# verify
self.assertEqual(True, actual)
[docs] def test_aabb_move(self):
# arrange
aabb = mut.AABB(1, 1, 5, 5)
# act
moved = aabb.move(3, 6)
# verify
self.assertEqual(mut.AABB(4, 7, 8, 11), moved)
[docs] def test_aabb_move_ip(self):
# arrange
aabb = mut.AABB(1, 1, 5, 5)
# act
aabb.move_ip(2, 4)
# verify
self.assertEqual(mut.AABB(3, 5, 7, 9), aabb)
[docs] def test_aabb_move_ip_center(self):
# arrange
aabb = mut.AABB(0, 0, 10, 10)
# act
aabb.move_ip(2, 4)
# verify
self.assertEqual(7, aabb.center_x)
self.assertEqual(9, aabb.center_y)
[docs] def test_aabb_collide_all(self):
# arrange
colliding = [
mut.AABB(11, 11, 20, 20),
mut.AABB(1, 1, 9, 9),
mut.AABB(1, 11, 9, 20),
mut.AABB(11, 1, 20, 9),
mut.AABB(2, 6, 20, 9),
mut.AABB(6, 2, 9, 20),
mut.AABB(6, 2, 9, 10),
mut.AABB(2, 6, 10, 9),
mut.AABB(12, 6, 19, 9),
mut.AABB(6, 12, 9, 19)]
others = list(colliding) # make a copy
others.extend([mut.AABB(1, 1, 3, 3),
mut.AABB(19, 10, 30, 13),
mut.AABB(1, 10, 3, 13),
mut.AABB(7, 19, 9, 33), ])
aabb = mut.AABB(5, 5, 15, 15)
# act
actual = aabb.collide_all(others)
# verify
self.assertEqual(10, len(actual))
self.assertEqual(colliding, actual)
[docs] def test_union_all(self):
# arrange
others = [
mut.AABB(11, 11, 20, 20),
mut.AABB(1, 1, 9, 9),
mut.AABB(1, 11, 9, 20),
mut.AABB(11, 1, 20, 9),
mut.AABB(2, 6, 20, 9),
mut.AABB(6, 2, 9, 20),
mut.AABB(6, 2, 9, 10),
mut.AABB(2, 6, 10, 9),
mut.AABB(12, 6, 19, 9),
mut.AABB(6, 12, 9, 19),
mut.AABB(1, 1, 3, 3),
mut.AABB(19, 10, 30, 13),
mut.AABB(1, 10, 3, 13),
mut.AABB(7, 19, 9, 33), ]
aabb = mut.AABB(3, 5, 8, 9)
# act
aabb_union = aabb.union_all(others)
# verify
expected = mut.AABB(1, 1, 30, 33)
self.assertEqual(expected, aabb_union)
[docs] def test_union(self):
# arrange
other = mut.AABB(1, 2, 30, 40)
aabb = mut.AABB(4, 20, 25, 25)
# act
union = aabb.union(other)
# verify
self.assertEqual(mut.AABB(1, 2, 30, 40), union)
[docs] def test_union2(self):
# arrange
aabb = mut.AABB(1, 2, 30, 40)
other = mut.AABB(4, 20, 25, 25)
# act
union = aabb.union(other)
# verify
self.assertEqual(mut.AABB(1, 2, 30, 40), union)
[docs] def test_copy_from(self):
# arrange
aabb = mut.AABB(1, 1, 2, 2)
source = mut.AABB(5, 6, 7, 8)
self.assertNotEqual(source, aabb)
# act
aabb.copy_from(source)
# verify
self.assertEqual(source, aabb)
[docs] def test_copy(self):
# arrange
aabb = mut.AABB(1, 2, 3, 4)
# act
aabb_copy = aabb.copy()
# verify
self.assertEqual(aabb, aabb_copy)
[docs] def test_str(self):
# arrange
aabb = mut.AABB(1, 2, 3, 4)
# act
s = str(aabb)
# verify
self.assertTrue(len(s) > 0)
[docs] def test_repr(self):
# arrange
aabb = mut.AABB(1, 2, 3, 4)
# act
s = aabb.__repr__()
# verify
self.assertTrue(len(s) > 0)
self.assertEqual("<AABB(1, 2, 3, 4)>", s)
[docs] def test_to_rect_tuple(self):
# arrange
aabb = mut.AABB(10, 20, 35, 40)
# act
rect_tuple = aabb.to_rect_tuple()
# assert
self.assertEqual((10, 20, 25, 20), rect_tuple)
def _invalid_sprite_definition_generator():
_INVALID_SPRITE_DEFINITIONS = [
((TestData.SDEF_INVALID_DUPLICATE_NAMES, ), {'test_name': "TestData.SDEF_INVALID_DUPLICATE_NAMES"}),
((TestData.SDEF_INVALID_MISSING_SPRITES, ), {'test_name': "TestData.SDEF_INVALID_MISSING_SPRITES"}),
((TestData.SDEF_INVALID_NEGATIVE_X_COORDINATES, ),
{'test_name': "TestData.SDEF_INVALID_NEGATIVE_X_COORDINATES"}),
((TestData.SDEF_INVALID_NEGATIVE_Y_COORDINATES, ),
{'test_name': "TestData.SDEF_INVALID_NEGATIVE_Y_COORDINATES"}),
((TestData.SDEF_INVALID_VERSION, ), {'test_name': "TestData.SDEF_INVALID_VERSION"}),
((TestData.SDEF_INVALID_MISSING_VERSION, ), {'test_name': "TestData.SDEF_INVALID_MISSING_VERSION"}),
((TestData.SDEF_INVALID_MISSING_SPRITE_NAME, ), {'test_name': "TestData.SDEF_INVALID_MISSING_SPRITE_NAME"}),
((TestData.SDEF_INVALID_MISSING_POINTS, ), {'test_name': "TestData.SDEF_INVALID_MISSING_POINTS"}),
((TestData.SDEF_INVALID_MISSING_POINT_COORDINATES, ),
{'test_name': "TestData.SDEF_INVALID_MISSING_POINT_COORDINATES"}),
((TestData.SDEF_INVALID_COLINEAR_COORDINATES_TRIANGLE, ),
{'test_name': "TestData.SDEF_INVALID_COLINEAR_COORDINATES_TRIANGLE"}),
((TestData.SDEF_INVALID_COLINEAR_COORDINATES_POLYGON, ),
{'test_name': "TestData.SDEF_INVALID_COLINEAR_COORDINATES_POLYGON"}),
((TestData.SDEF_INVALID_COLINEAR_2_POINTS_SAME, ),
{'test_name': "TestData.SDEF_INVALID_COLINEAR_2_POINTS_SAME"}),
((TestData.SDEF_INVALID_COLINEAR_3_POINTS_SAME, ),
{'test_name': "TestData.SDEF_INVALID_COLINEAR_3_POINTS_SAME"}),
((TestData.SDEF_INVALID_MISSING_SPRITES_LIST_EMPTY, ),
{'test_name': "TestData.SDEF_INVALID_MISSING_SPRITES_LIST_EMPTY"}),
((TestData.SDEF_INVALID_INCONSISTENT_ORIENTATION, ),
{'test_name': "TestData.SDEF_INVALID_INCONSISTENT_ORIENTATION"}),
((TestData.SDEF_INVALID_MISSING_FILENAME, ), {'test_name': "TestData.SDEF_INVALID_MISSING_FILENAME"}),
((TestData.SDEF_INVALID_FILENAME_EMPTY, ), {'test_name': "TestData.SDEF_INVALID_FILENAME_EMPTY"}),
]
for item in _INVALID_SPRITE_DEFINITIONS:
yield item
@ddtd.use_data_driven_testing_decorators
[docs]class TestSpriteDefinitionValidation(unittest.TestCase):
[docs] def setUp(self):
# arrange
self.logger_mock = LoggerMock()
[docs] def test_is_valid(self):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
# act
actual = sut.is_sprite_def_valid(TestData.SDEF_GRID_2X2)
# verify
self.assertTrue(actual)
@ddtd.test_case_from_generator(_invalid_sprite_definition_generator)
def test_sprite_definition_is_invalid(self, sdef):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
# act
actual = sut.is_sprite_def_valid(sdef)
# verify
self.assertFalse(actual)
@ddtd.test_case_from_generator(_invalid_sprite_definition_generator)
def test_sprite_definition_is_invalid_logs_error_message(self, sdef):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
# act
sut.is_sprite_def_valid(sdef)
# verify
self.assertEqual(2, len(self.logger_mock.messages), self.logger_mock.messages)
self.assertEqual(logging.ERROR, self.logger_mock.messages[1][0], self.logger_mock.messages)
[docs] def test_sprite_definition_logs_warning(self):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
# act
sut.is_sprite_def_valid(TestData.SDEF_WARN_2_POINTS_SAME_IN_POLYGON)
# verify
self.assertEqual(2, len(self.logger_mock.messages))
self.assertEqual(logging.WARN, self.logger_mock.messages[1][0])
[docs] def test_sprite_definition_is_invalid_if_None(self):
# arrange
sut = mut.SpritesheetLib10(self.logger_mock)
# act
actual = sut.is_sprite_def_valid(None)
# verify
self.assertFalse(actual)
self.assertEqual(logging.ERROR, self.logger_mock.messages[1][0])
import os
import sys
if sys.version_info[0] < 3:
# Python 3.x renames the built-in module
_bi = '__builtin__' # pragma: no cover
else:
_bi = 'builtins' # pragma: no cover
__builtin__ = __import__(_bi)
# class FileMock(object):
# """
# The file mock simulates a file object of python.
# """
#
# def __exit__(self, exc_type, exc_val, exc_tb):
# pass
#
# def __enter__(self):
# return self
#
# # noinspection PyMethodMayBeStatic,PyUnusedLocal
# def readlines(self, *args):
# """
# Reads the lines of this file like object.
# :param args: Any arguments, unused.
# :return: The lines.
# """
# return []
[docs]class TestFileInfoOpen(unittest.TestCase):
[docs] def setUp(self):
self.method_calls = [] # [(name, args), ]
self.file_mock = object()
self.orig_open = __builtin__.open
__builtin__.open = self.mocked_open
[docs] def tearDown(self):
self.reset_builtin()
[docs] def reset_builtin(self):
__builtin__.open = self.orig_open
[docs] def mocked_open(self, *args):
self.method_calls.append(("open", args))
return self.file_mock
[docs] def test_open_same_casing(self):
# arrange
does_file_exist = True
os_path_mock = OsPathMock(does_file_exist)
list_dir = ["a.txt", "b.txt"]
os_module_mock = OsModuleMock(os_path_mock, list_dir)
sut = FileInfo("a.txt", os_module_mock)
# act
f = sut.open(mut.FileMode.ReadBinary)
self.reset_builtin() # needs to be here to have no side effects in the assertions
# verify
self.assertIs(self.file_mock, f)
[docs] def test_open_different_casing(self):
# arrange
does_file_exist = True
os_path_mock = OsPathMock(does_file_exist)
list_dir = ["A.txt", "b.txt"]
os_module_mock = OsModuleMock(os_path_mock, list_dir)
sut = FileInfo("a.txt", os_module_mock)
# act
self.assertRaises(IOError, sut.open, mut.FileMode.ReadBinary)
@ddtd.use_data_driven_testing_decorators
[docs]class TestFileInfo(unittest.TestCase):
[docs] def test_directory_is_passed(self):
# arrange
directory_path = os.path.abspath("../tests")
# act / verify
self.assertRaises(ValueError, FileInfo, directory_path)
[docs] def test_is_casing_different_True(self):
# arrange
does_file_exist = True
os_path_mock = OsPathMock(does_file_exist)
list_dir = ["a.txt", "b.txt"]
os_module_mock = OsModuleMock(os_path_mock, list_dir)
fi = mut.FileInfo("A.txt", os_module_mock)
# act
actual = fi.is_casing_different
# verify
self.assertTrue(actual)
[docs] def test_is_casing_different_True_no_exists(self):
# arrange
does_file_exist = False
os_path_mock = OsPathMock(does_file_exist)
list_dir = ["a.txt", "b.txt"]
os_module_mock = OsModuleMock(os_path_mock, list_dir)
fi = mut.FileInfo("A.txt", os_module_mock)
# act
actual = fi.is_casing_different
# verify
self.assertFalse(actual)
[docs] def test_is_casing_different_False(self):
# arrange
does_file_exist = True
os_path_mock = OsPathMock(does_file_exist)
list_dir = ["a.txt", "b.txt"]
os_module_mock = OsModuleMock(os_path_mock, list_dir)
fi = mut.FileInfo("b.txt", os_module_mock)
# act
actual = fi.is_casing_different
# verify
self.assertFalse(actual)
[docs] def test_is_casing_different_False_no_exists(self):
# arrange
does_file_exist = False
os_path_mock = OsPathMock(does_file_exist)
list_dir = ["a.txt", "b.txt"]
os_module_mock = OsModuleMock(os_path_mock, list_dir)
fi = mut.FileInfo("b.txt", os_module_mock)
# act
actual = fi.is_casing_different
# verify
self.assertFalse(actual)
# def test_file_does_not_exist_due_casing(self):
# # arrange
# does_file_exist = True
# os_path_mock = OsPathMock(does_file_exist)
# list_dir = ["a.txt", "b.py"]
# os_module_mock = OsModuleMock(os_path_mock, list_dir)
# fi = mut.FileInfo("B.py", os_module_mock)
#
# # act
# actual = fi.exists
#
# # verify
# self.assertFalse(actual)
[docs] def test_file_does_exist_with_correct_casing(self):
# arrange
does_file_exist = True
os_path_mock = OsPathMock(does_file_exist)
list_dir = ["a.txt", "b.py"]
os_module_mock = OsModuleMock(os_path_mock, list_dir)
fi = mut.FileInfo("b.py", os_module_mock)
# act
actual = fi.exists
# verify
self.assertTrue(actual)
[docs] def test_file_does_exists(self):
# TODO: rewrite to use the os and os.path mock to remove disk access
# arrange
fi = mut.FileInfo("test_spritesheetlib.py")
# act
actual = fi.exists
# verify
self.assertTrue(actual)
[docs] def test_file_does_not_exists(self):
# TODO: rewrite to use the os and os.path mock to remove disk access
# arrange
fi = mut.FileInfo("/tests/non-existing.txt")
# act
actual = fi.exists
# verify
self.assertFalse(actual)
[docs] def test_io_error_is_raised_for_non_existing(self):
# TODO: rewrite to use the os and os.path mock to remove disk access
# arrange
fi = mut.FileInfo("/test/non-existing.txt")
# act / verify
self.assertRaises(IOError, fi.open, mut.FileMode.ReadBinary)
@ddtd.test_case(mut.FileMode.Read)
@ddtd.test_case(mut.FileMode.ReadUpdate)
@ddtd.test_case(mut.FileMode.ReadUniversalNewLines)
@ddtd.test_case(mut.FileMode.ReadText)
def test_open_read_using_mode(self, mode):
# TODO: rewrite to use the os and os.path mock to remove disk access??
# arrange
fi = mut.FileInfo(self.file_name)
with fi.open(mut.FileMode.Write) as temp:
temp.write("hello")
# act
with fi.open(mode) as fp:
content = fp.readline()
# verify
self.assertEqual("hello", content)
self.assertFalse(fp.closed)
self.assertTrue(fp.closed)
@ddtd.test_case(mut.FileMode.ReadBinary)
@ddtd.test_case(mut.FileMode.ReadUpdateBinary)
def test_open_read_using_mode_binary(self, mode):
# TODO: rewrite to use the os and os.path mock to remove disk access??
# arrange
fi = mut.FileInfo(self.file_name)
with fi.open(mut.FileMode.WriteBinary) as temp:
temp.write(b"hello")
# act
with fi.open(mode) as fp:
content = fp.readline()
# verify
self.assertEqual(b"hello", content)
self.assertFalse(fp.closed)
self.assertTrue(fp.closed)
@ddtd.test_case(mut.FileMode.Write)
@ddtd.test_case(mut.FileMode.WriteUpdate)
@ddtd.test_case(mut.FileMode.Append)
@ddtd.test_case(mut.FileMode.AppendUpdate)
@ddtd.test_case(mut.FileMode.WriteText)
def test_open_write_with_mode(self, mode):
# TODO: rewrite to use the os and os.path mock to remove disk access??
# arrange
fi = mut.FileInfo(self.file_name)
with fi.open(mode) as temp:
temp.write("hello")
# act
with fi.open(mut.FileMode.ReadBinary) as fp:
content = fp.readline()
# verify
self.assertEqual(b"hello", content)
self.assertFalse(fp.closed)
self.assertTrue(fp.closed)
@ddtd.test_case(mut.FileMode.WriteBinary)
@ddtd.test_case(mut.FileMode.WriteUpdateBinary)
@ddtd.test_case(mut.FileMode.AppendBinary)
@ddtd.test_case(mut.FileMode.AppendUpdateBinary)
def test_open_write_with_mode_binary(self, mode):
# TODO: rewrite to use the os and os.path mock to remove disk access??
# arrange
fi = mut.FileInfo(self.file_name)
with fi.open(mode) as temp:
temp.write(b"hello")
# act
with fi.open(mut.FileMode.ReadBinary) as fp:
content = fp.readline()
# verify
self.assertEqual(b"hello", content)
self.assertFalse(fp.closed)
self.assertTrue(fp.closed)
[docs] def test_file_info_does_not_accept_a_directory_path(self):
# arrange
dir_path = "."
# act / verify
self.assertRaises(ValueError, mut.FileInfo, dir_path)
[docs] def test_file_info_does_not_accept_a_directory_path_with_sep(self):
# arrange
dir_path = os.path.join(os.curdir, "test", os.sep)
# act / verify
self.assertRaises(ValueError, mut.FileInfo, dir_path)
[docs] def test_file_info_does_not_accept_a_directory_path_with_altsep(self):
# arrange
dir_path = os.path.join(os.curdir, "test", os.altsep)
# act / verify
self.assertRaises(ValueError, mut.FileInfo, dir_path)
[docs] def test_file_info_does_not_accept_a_directory_path_with_pardir(self):
# arrange
dir_path = os.path.join(os.curdir, "test", os.pardir)
# act / verify
self.assertRaises(ValueError, mut.FileInfo, dir_path)
[docs] def test_file_info_accepts_file_without_extension(self):
# arrange
file_name = os.path.join(os.curdir, "test", "test_file")
# act / verify
mut.FileInfo(file_name)
[docs] def test_file_info_raises_if_file_name_contains_pathsep(self):
# arrange
file_name = os.path.join("test.txt" + os.pathsep + os.curdir, "test", "test_file.txt")
# act / verify
self.assertRaises(ValueError, mut.FileInfo, file_name)
[docs] def test_file_info_raises_on_null_path(self):
# arrange
file_path = os.devnull
# act / verify
self.assertRaises(ValueError, mut.FileInfo, file_path)
[docs] def test_file_info_delete(self):
# arrange
fi = mut.FileInfo(self.file_name)
with fi.open(mut.FileMode.Write) as f:
f.write("hello")
# act
self.assertTrue(fi.exists)
fi.delete()
# verify
self.assertFalse(fi.exists)
[docs] def test_name_property(self):
# arrange
file_name_and_path = os.path.join("subdir", "sub-sub-dir", self.file_name)
fi = mut.FileInfo(file_name_and_path)
# act
name = fi.name
# verify
self.assertEqual(self.file_name, name)
[docs] def test_directory_name_property(self):
# arrange
directory_full_path = os.path.join("subdir", "sub-sub-dir")
file_name_and_path = os.path.join(directory_full_path, self.file_name)
fi = mut.FileInfo(file_name_and_path)
# act
name = fi.directory_name
# verify
expected = directory_full_path
if os.path.altsep is not None:
expected = expected.replace(os.path.sep, os.path.altsep)
self.assertEqual(expected, name)
[docs] def test_directory_name_property_case(self):
# arrange
directory_full_path = os.path.join("subDir", "SubSubDir")
file_name_and_path = os.path.join(directory_full_path, self.file_name)
fi = mut.FileInfo(file_name_and_path)
# act
name = fi.directory_name
# verify
expected = directory_full_path
if os.path.altsep is not None:
expected = expected.replace(os.path.sep, os.path.altsep)
self.assertEqual(expected, name)
[docs] def setUp(self):
self.file_name = "temp.txt"
[docs] def tearDown(self):
remove_file(mut.FileInfo(self.file_name))
[docs] def test_fi_are_not_equal(self):
# arrange
fi = mut.FileInfo(self.file_name)
other = mut.FileInfo("a.txt")
# act
actual = fi != other
# verify
self.assertEqual(True, actual)
[docs] def test_fi_not_equal_to_other_type(self):
# arrange
fi = mut.FileInfo(self.file_name)
other = object()
# act
actual = fi != other
# verify
self.assertEqual(True, actual)
[docs] def test_fi_not_equal_false(self):
# arrange
fi = mut.FileInfo(self.file_name)
other = mut.FileInfo(self.file_name + ".json")
# act
actual = fi == other
# verify
self.assertEqual(False, actual)
[docs] def test_fi_equal_to_other_type(self):
# arrange
fi = mut.FileInfo(self.file_name)
other = mut.AABB(1, 2, 3, 4)
# act
actual = fi == other
# verify
self.assertEqual(False, actual)
[docs] def test_fi_are_equal(self):
# arrange
fi = mut.FileInfo(self.file_name)
other = mut.FileInfo(self.file_name)
# act
actual = fi == other
# verify
self.assertEqual(True, actual)
[docs] def test_fi_fullname(self):
# arrange
directory_full_path = os.path.join("subdir", "sub-sub-dir")
file_name_and_path = os.path.join(directory_full_path, self.file_name)
fi = mut.FileInfo(file_name_and_path)
# act
name = fi.full_name
# verify
expected = file_name_and_path
if os.path.altsep is not None:
expected = expected.replace(os.path.sep, os.path.altsep)
self.assertEqual(expected, name)
[docs] def test_fi_fullname_case(self):
# arrange
directory_full_path = os.path.join("subDir", "SubSubdir")
file_name_and_path = os.path.join(directory_full_path, self.file_name)
fi = mut.FileInfo(file_name_and_path)
# act
name = fi.full_name
# verify
expected = file_name_and_path
if os.path.altsep is not None:
expected = expected.replace(os.path.sep, os.path.altsep)
self.assertEqual(expected, name)
[docs] def test_fi_fullname_normpath(self):
# arrange
directory_full_path = "subDir/SubSubdir"
file_name_and_path = directory_full_path + "\\" + self.file_name
fi = mut.FileInfo(file_name_and_path)
# act
name = fi.full_name
# verify
expected = os.path.normpath(file_name_and_path)
if os.path.altsep is not None:
expected = expected.replace(os.path.sep, os.path.altsep)
self.assertEqual(expected, name)
[docs] def test_str(self):
# arrange
aabb = mut.FileInfo(self.file_name)
# act
s = str(aabb)
# verify
self.assertTrue(len(s) > 0)
[docs] def test_repr(self):
# arrange
aabb = mut.FileInfo(self.file_name)
# act
s = aabb.__repr__()
# verify
self.assertTrue(len(s) > 0)
self.assertEqual("<FileInfo('{0}')>".format(self.file_name), s)
[docs]class TestPolygon(unittest.TestCase):
points = [[0, 0], [10, 0], [10, 10], [0, 10]]
[docs] def test_sign_positive(self):
# arrange
positive = 23
# act
actual = mut.sign(positive)
# verify
self.assertEqual(mut.PolygonOrientation.Clockwise, actual)
[docs] def test_sign_negative(self):
# arrange
negative = -55
# act
actual = mut.sign(negative)
# verify
self.assertEqual(mut.PolygonOrientation.CounterClockwise, actual)
[docs] def test_sign_zero(self):
# arrange
zero = 0.0
# act
actual = mut.sign(zero)
# verify
self.assertEqual(zero, actual)
[docs] def test_signed_area_positive(self):
# arrange
# act
actual = mut.get_signed_area_of_polygon(TestPolygon.points)
# verify
area = 100
self.assertEqual(area * mut.PolygonOrientation.CounterClockwise, actual)
[docs] def test_signed_area_negative(self):
# arrange
# act
actual = mut.get_signed_area_of_polygon(reversed(TestPolygon.points))
# verify
area = 100
self.assertEqual(area * mut.PolygonOrientation.Clockwise, actual)
[docs] def test_area_clockwise(self):
# arrange
# act
actual = mut.get_area_of_polygon(TestPolygon.points)
# verify
area = 100
self.assertEqual(area, actual)
[docs] def test_area_counterclockwise(self):
# arrange
# act
actual = mut.get_area_of_polygon(reversed(TestPolygon.points))
# verify
area = 100
self.assertEqual(area, actual)
[docs] def test_get_orientation_counter_clockwise(self):
# arrange
# act
actual = mut.get_orientation(TestPolygon.points)
# verify
self.assertEqual(mut.PolygonOrientation.CounterClockwise, actual)
[docs] def test_get_orientation_clockwise(self):
# arrange
# act
actual = mut.get_orientation(reversed(TestPolygon.points))
# verify
self.assertEqual(mut.PolygonOrientation.Clockwise, actual)
[docs]class FileInfoMock(mut.FileInfo):
"""
The mock object for the FileInfo class.
:param file_path: The file path to store.
:param exists_value: Bool, the value if the path exists.
"""
def __init__(self, file_path, exists_value):
mut.FileInfo.__init__(self, file_path)
self._captured_text = None
self.open_args = None
self.close_args = None
self.exists_value = exists_value
self.method_calls = [] # [(method_name, args), ]
@property
def exists(self):
"""
The exists property.
:return: Returns the exists_value given in the constructor.
"""
return self.exists_value
[docs] def open(self, *args, **kwargs):
"""
Opens the file. This mocked method returns itself as file object.
It saves the arguments in open_args = (args, kwargs)
:param args: The passed arguments.
:param kwargs: The passed keyword arguments.
:return: Itself as file object.
"""
self.method_calls.append((FileInfoMock.open.__name__, args))
self.open_args = (args, kwargs)
return self
# def close(self, *args, **kwargs):
# self.close_args = (args, kwargs)
[docs] def write(self, *args):
"""
Write something to the file like object.
:param args: The data to write. This data is saved in _captured_text.
"""
self.method_calls.append((FileInfoMock.write.__name__, args))
self._captured_text = args
[docs] def read(self):
"""
Read the file like object.
:return: Returns the contents of _captured_text (see write)
"""
self.method_calls.append((FileInfoMock.read.__name__, tuple()))
return self._captured_text
[docs] def delete(self):
"""
Deletes the file.
"""
self.method_calls.append((FileInfoMock.delete.__name__, tuple()))
# TODO: this would be more correct but breaks currently a test case (maybe it needs a rewrite?)
# self.exists_value = False
def __enter__(self):
return self
def __exit__(self, exc_type, exc_val, exc_tb):
pass
[docs] def getvalue(self):
"""
Returns the contents of _captured_text.
:return: Contents of _captured_text (see write and read methods).
"""
return self._captured_text
[docs]class TestFileInfoMock(unittest.TestCase):
[docs] def test_mock_exist_returns_true(self):
# arrange
sut = FileInfoMock("xxx", True)
# act / verify
self.assertTrue(sut.exists)
[docs] def test_mock_exist_returns_false(self):
# arrange
sut = FileInfoMock("yyy", False)
# act / verify
self.assertFalse(sut.exists)
[docs] def test_write_to_file(self):
# arrange
fi = FileInfoMock("out.path", False)
f = fi.open(mut.FileMode.Write)
data = u"hello"
# act
f.write(data)
# verify
self.assertTrue(data, f.getvalue())
# noinspection PyNoneFunctionAssignment
[docs] def test_read_from_file(self):
# arrange
fi = FileInfoMock("out.path", False)
f = fi.open(mut.FileMode.Write)
data = u"hello"
f.write(data)
# act
actual = f.read()
# verify
self.assertTrue(data, actual)
[docs]def remove_file(file_info, logger_instance=logger):
# noinspection PyBroadException
"""
Tries to remove the given file. It will log an error if the file could not be removed.
:param logger_instance: The logger instance to use. Defaults to the module logger.
:param file_info: The filename to be removed.
"""
try:
file_info.delete()
except Exception as ex:
if file_info.exists:
logger_instance.error("ex: failed to remove file " + file_info.name + " with exception " + str(ex))
finally:
if file_info.exists:
logger_instance.error("failed to remove file, it still exists: " + file_info.name)
[docs]class TestRemoveFile(unittest.TestCase):
[docs] def test_remove_existing_file(self):
# arrange
self.file_name = "temp1.txt"
# TODO: revise this unittest, it should be using mut.FileInfo and a os_module_mock!
file_info_mock = FileInfoMock(self.file_name, True)
# act
remove_file(file_info_mock)
# verify
self.assertEqual((FileInfoMock.delete.__name__, tuple()), file_info_mock.method_calls[0])
[docs] def test_remove_fails(self):
# arrange
# noinspection PyDocstring
class FileInfoMockFailingDelete(FileInfoMock):
def delete(self):
raise Exception("Mocked delete failed")
self.file_name = "temp2.txt"
file_info_mock = FileInfoMockFailingDelete(self.file_name, True)
logger_mock = LoggerMock()
# act
remove_file(file_info_mock, logger_mock)
# verify
self.assertTrue(logger_mock.messages[0][1].startswith("ex: failed to remove file " + self.file_name))
[docs] def test_remove_but_file_still_exists(self):
# arrange
self.file_name = "temp3.txt"
# TODO: revise this unittest, it should be using mut.FileInfo and a os_module_mock!
file_info_mock = FileInfoMock(self.file_name, True)
logger_mock = LoggerMock()
# act
remove_file(file_info_mock, logger_mock)
# verify
self.assertTrue(logger_mock.messages[0][1].startswith("failed to remove file, it still exists: "))
[docs]class TestNeededDigitsFromValue(unittest.TestCase):
[docs] def test_zero(self):
# arrange
value = 0
# act
num_digits = mut.get_needed_digits(value)
# verify
self.assertAlmostEqual(1, num_digits)
[docs] def test_value_9(self):
# arrange
value = 9
# act
num_digits = mut.get_needed_digits(value)
# verify
self.assertAlmostEqual(1, num_digits)
[docs] def test_value_10(self):
# arrange
value = 10
# act
num_digits = mut.get_needed_digits(value)
# verify
self.assertAlmostEqual(2, num_digits)
[docs] def test_value_100(self):
# arrange
value = 100
# act
num_digits = mut.get_needed_digits(value)
# verify
self.assertAlmostEqual(3, num_digits)
[docs] def test_value_1000(self):
# arrange
value = 1000
# act
num_digits = mut.get_needed_digits(value)
# verify
self.assertAlmostEqual(4, num_digits)
[docs] def test_value_10000(self):
# arrange
value = 10000
# act
num_digits = mut.get_needed_digits(value)
# verify
self.assertAlmostEqual(5, num_digits)
[docs] def test_non_int_raises_TypeError(self):
# arrange
value = 45.234
# act / verify
self.assertRaises(TypeError, mut.get_needed_digits, value)
[docs] def test_negative_values_raise_ValueError(self):
# arrange
value = -23
# act / verify
self.assertRaises(ValueError, mut.get_needed_digits, value)
[docs]class JsonMock(object):
"""
The JsonMock.
:param load_value: The value that the method load() will return.
"""
def __init__(self, load_value=None, loads_value=None):
self.load_value = load_value
self.loads_value = loads_value
self.method_calls = [] # [(name, args), ]
[docs] def load(self, fp, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None,
object_pairs_hook=None, **kw):
"""
The load method. It would load a json from a file, but this mock just returns the load_value given through
the constructor. All other arguments are stored, but ignored.
:param fp:
:param encoding:
:param cls:
:param object_hook:
:param parse_float:
:param parse_int:
:param parse_constant:
:param object_pairs_hook:
:param kw:
:return: Returns the value given by the constructor.
"""
self.method_calls.append((JsonMock.load.__name__, (
fp, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, kw)))
return self.load_value
[docs] def loads(self, s, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None, parse_constant=None,
object_pairs_hook=None, **kw):
"""
The load method. It would load a json from a string, but this mock just returns the loads_value given through
the constructor. All other arguments are stored, but ignored.
:param s:
:param encoding:
:param cls:
:param object_hook:
:param parse_float:
:param parse_int:
:param parse_constant:
:param object_pairs_hook:
:param kw:
:return: Returns the value given by the constructor.
"""
self.method_calls.append((JsonMock.loads.__name__, (
s, encoding, cls, object_hook, parse_float, parse_int, parse_constant, object_pairs_hook, kw)))
return self.loads_value
[docs]class TestJsonMock(unittest.TestCase):
[docs] def test_load(self):
# arrange
load_value = "blb"
sut = JsonMock(load_value)
# act
actual = sut.load(None)
# verify
self.assertEqual(load_value, actual)
self.assertEqual(JsonMock.load.__name__, sut.method_calls[0][0])
[docs] def test_loads(self):
# arrange
load_value = "blb"
sut = JsonMock(loads_value=load_value)
# act
actual = sut.loads(None)
# verify
self.assertEqual(load_value, actual)
self.assertEqual(JsonMock.loads.__name__, sut.method_calls[0][0])
# noinspection PyDocstring
[docs]class OsPathMock(object):
"""
The os.path module Mock.
:param does_file_exist: The value that exists() should return.
"""
def __init__(self, does_file_exist, is_dir=False):
self._does_file_exist = does_file_exist
self.method_calls = [] # [(name, args), ]
self._is_dir = is_dir
[docs] def dirname(self, path_name):
self.method_calls.append((OsPathMock.dirname.__name__, (path_name,)))
return self.split(path_name)[0]
[docs] def split(self, path_name):
self.method_calls.append((OsPathMock.split.__name__, (path_name,)))
return os.path.split(path_name)
[docs] def exists(self, path_name):
self.method_calls.append((OsPathMock.exists.__name__, (path_name,)))
return self._does_file_exist
[docs] def isdir(self, path_name):
self.method_calls.append((OsPathMock.isdir.__name__, (path_name,)))
return self._is_dir
# noinspection PyDocstring
[docs]class OsModuleMock(object):
"""
The os module mock.
:param path_module: The os.path module mock.
:param list_dir: The list that should be returned when listdir() is called.
"""
def __init__(self, path_module, list_dir):
self.path = path_module
self._list_dir = list_dir
self.method_calls = [] # [(name, args), ]
[docs] def remove(self, file_path):
self.method_calls.append((OsModuleMock.remove.__name__, (file_path,)))
[docs] def listdir(self, directory):
self.method_calls.append((OsModuleMock.listdir.__name__, (directory,)))
return self._list_dir
[docs]class TestOsPathMock(unittest.TestCase):
[docs] def test_directory_name(self):
# arrange
sut = OsPathMock(True)
directory = "dir/Dir"
p = directory + "/file_name.png"
# act
actual = sut.dirname(p)
# verify
self.assertEqual(directory, actual)
self.assertEqual((OsPathMock.dirname.__name__, (p,),), sut.method_calls[0])
[docs] def test_split(self):
# arrange
sut = OsPathMock(True)
directory = "dir/Dir"
f = "file_name.png"
p = directory + "/" + f
# act
actual = sut.split(p)
# verify
self.assertEqual(directory, actual[0])
self.assertEqual(f, actual[1])
self.assertEqual((OsPathMock.split.__name__, (p,),), sut.method_calls[0])
[docs] def test_exists_false(self):
# arrange
sut = OsPathMock(False)
# act
arg = "bla"
actual = sut.exists(arg)
# verify
self.assertFalse(actual)
self.assertEqual((OsPathMock.exists.__name__, (arg,),), sut.method_calls[0])
[docs] def test_exists_true(self):
# arrange
sut = OsPathMock(True)
arg = "bla"
# act
actual = sut.exists(arg)
# verify
self.assertTrue(actual)
self.assertEqual((OsPathMock.exists.__name__, (arg,),), sut.method_calls[0])
[docs] def test_is_dir_true(self):
# arrange
sut = OsPathMock(True, True)
arg = "bla"
# act
actual = sut.isdir(arg)
# verify
self.assertTrue(actual)
self.assertEqual((OsPathMock.isdir.__name__, (arg,),), sut.method_calls[0])
[docs] def test_is_dir_false(self):
# arrange
sut = OsPathMock(True)
arg = "bla"
# act
actual = sut.isdir(arg)
# verify
self.assertFalse(actual)
self.assertEqual((OsPathMock.isdir.__name__, (arg,),), sut.method_calls[0])
[docs]class TestOsModuleMock(unittest.TestCase):
[docs] def test_listdir(self):
# arrange
pm = OsPathMock(False)
list_dir = [1, 3, 5, 7]
sut = OsModuleMock(pm, list_dir)
arg = "bar"
# act
actual = sut.listdir(arg)
# verify
self.assertEqual(list_dir, actual)
self.assertIs(list_dir, actual)
self.assertEqual((OsModuleMock.listdir.__name__, (arg,),), sut.method_calls[0])
[docs] def test_remove(self):
# arrange
pm = OsPathMock(False)
list_dir = [1, 3, 5, 7]
sut = OsModuleMock(pm, list_dir)
arg = "image.gif"
# act
sut.remove(arg)
# verify
self.assertEqual((OsModuleMock.remove.__name__, (arg,),), sut.method_calls[0])
[docs]class SpritesheetLib10SpecialMock(SpritesheetLib10):
"""
The special mock to log the call to 'load_spritesheet_from_sdef'.
:param the_logger: The logger instance to use.
"""
def __init__(self, sprites, sdef, the_logger):
SpritesheetLib10.__init__(self, the_logger)
self.method_calls = [] # [(method_name, (args)), ]
self.sprites = sprites
self.sdef = sdef
# noinspection PyDocstring
[docs] def load_sdef_from_file(self, *args):
return self.sdef
# noinspection PyDocstring
[docs] def load_spritesheet_from_sdef(self, *args):
self.method_calls.append((self.load_spritesheet_from_sdef.__name__, args))
return self.sprites
[docs]class TestSpritesheetLibLoadingSpriteDefinition(unittest.TestCase):
[docs] def setUp(self):
# arrange
self.logger_mock = LoggerMock()
[docs] def test_load_sdef_from_file_existing(self):
# arrange
lib = mut.SpritesheetLib10(self.logger_mock)
sdef_file_name = "test.sdef.png.sdef"
sdef_file_info = FileInfoMock(sdef_file_name, True)
sdef_file_info.write(TestData.SDEF_GRID_2X2_TEST)
json_mock = JsonMock(TestData.SDEF_GRID_2X2_TEST)
# act
actual = lib.load_sdef_from_file(sdef_file_info, json_mock)
# verify
expected = TestData.SDEF_GRID_2X2_TEST
self.maxDiff = None
self.assertDictEqual(expected, actual)
[docs] def test_load_sdef_from_file_not_existing(self):
# arrange
lib = mut.SpritesheetLib10(self.logger_mock)
sdef_file_name = "test.sdef.PNG.sdef"
sdef_file_info = FileInfoMock(sdef_file_name, True)
sdef_file_info.write(TestData.SDEF_GRID_2X2_TEST)
json_mock = JsonMock(TestData.SDEF_GRID_2X2_TEST)
# act / verify
self.assertRaises(ValueError, lib.load_sdef_from_file, sdef_file_info, json_mock)
[docs] def test_load_sdef_from_file_raises(self):
# arrange
# noinspection PyDocstring
class JsonMockRaising(JsonMock):
def load(self, fp, encoding=None, cls=None, object_hook=None, parse_float=None, parse_int=None,
parse_constant=None, object_pairs_hook=None, **kw):
JsonMock.load(self, fp, encoding, cls, object_hook, parse_float, parse_int, parse_constant,
object_pairs_hook)
raise ValueError("bla")
lib = mut.SpritesheetLib10(self.logger_mock)
sdef_file_name = "test-non-existing.png.sdef"
sdef_file_info = FileInfoMock(sdef_file_name, True)
sdef_file_info.write(TestData.SDEF_GRID_2X2_TEST)
json_mock = JsonMockRaising(TestData.SDEF_GRID_2X2_TEST)
# act / verify
self.assertRaises(ValueError, lib.load_sdef_from_file, sdef_file_info, json_mock)
[docs] def test_load_spritesheet(self):
# arrange
sprites = {'001': 'bla', '002': 'blu'}
sut = SpritesheetLib10SpecialMock(sprites, TestData.SDEF_GRID_2X2_TEST, self.logger_mock)
image_path = "test.sdef.png"
definition_file_info = FileInfo(image_path + ".sdef")
# act
actual = sut.load_spritesheet(definition_file_info)
# verify that the method has been called
self.assertEqual(sut.load_spritesheet_from_sdef.__name__, sut.method_calls[0][0])
# verify that the arguments where right
sdef = sut.method_calls[0][1][0]
self.assertEqual(TestData.SDEF_GRID_2X2_TEST, sdef)
image_file_info = sut.method_calls[0][1][1]
self.assertEqual(FileInfo(image_path), image_file_info)
# verify return value
self.assertDictEqual(sprites, actual)
[docs] def test_load_spritesheet_with_dir_path(self):
# arrange
sprites = {'001': 'bla', '002': 'blu'}
sut = SpritesheetLib10SpecialMock(sprites, TestData.SDEF_GRID_2X2_TEST, self.logger_mock)
image_path = "images\\walk\\test.sdef.png"
definition_file_info = FileInfo(image_path + ".sdef")
# act
actual = sut.load_spritesheet(definition_file_info)
# verify that the method has been called
self.assertEqual(sut.load_spritesheet_from_sdef.__name__, sut.method_calls[0][0])
# verify that the arguments where right
sdef = sut.method_calls[0][1][0]
self.assertEqual(TestData.SDEF_GRID_2X2_TEST, sdef)
image_file_info = sut.method_calls[0][1][1]
self.assertEqual(FileInfo(image_path), image_file_info)
# verify return value
self.assertDictEqual(sprites, actual)
[docs] def test_load_spritesheet_sdef_is_replaced_correctly(self):
# arrange
sprites = {'001': 'bla', '002': 'blu'}
sut = SpritesheetLib10SpecialMock(sprites, TestData.SDEF_GRID_2X2_TEST, self.logger_mock)
image_path = os.path.normpath("images/walk/test.sdef.png")
definition_file_info = FileInfo(image_path + ".sdef")
# act
actual = sut.load_spritesheet(definition_file_info)
# verify that the method has been called
self.assertEqual(sut.load_spritesheet_from_sdef.__name__, sut.method_calls[0][0])
# verify that the arguments where right
sdef = sut.method_calls[0][1][0]
self.assertEqual(TestData.SDEF_GRID_2X2_TEST, sdef)
image_file_info = sut.method_calls[0][1][1]
self.assertEqual(FileInfo(image_path), image_file_info)
# verify return value
self.assertDictEqual(sprites, actual)
[docs] def test_load_spritesheet_is_loaded_with_different_extension(self):
# arrange
sprites = {'001': 'bla', '002': 'blu'}
sut = SpritesheetLib10SpecialMock(sprites, TestData.SDEF_GRID_2X2_TEST, self.logger_mock)
image_path = "images\\walk\\test.sdef.png"
definition_file_info = FileInfo(image_path + ".spr")
# act
actual = sut.load_spritesheet(definition_file_info)
# verify that the method has been called
self.assertEqual(sut.load_spritesheet_from_sdef.__name__, sut.method_calls[0][0])
# verify that the arguments where right
sdef = sut.method_calls[0][1][0]
self.assertEqual(TestData.SDEF_GRID_2X2_TEST, sdef)
image_file_info = sut.method_calls[0][1][1]
self.assertEqual(FileInfo(image_path), image_file_info)
# verify return value
self.assertDictEqual(sprites, actual)
def _create_pygame_module_mock(self):
sprite_sheet_surf = PygameSurfaceMock([], [], "spritesheet")
images = [sprite_sheet_surf]
draw_rects = [PygameRectMock((1, 1), "draw_rect1"), PygameRectMock((1, 2), "draw_rect2"),
PygameRectMock((1, 3), "draw_rect3"), PygameRectMock((1, 4), "draw_rect4")]
image_mock = PygameImageModuleMock(images)
draw_mock = PygameDrawModuleMock(draw_rects)
modules = {PygameMock.IMAGE_MODULE_NAME: image_mock, PygameMock.DRAW_MODULE_NAME: draw_mock}
mask1 = PygameSurfaceMock([], [PygameRectMock((1, 0), "mask_rect1")], "mask1")
mask2 = PygameSurfaceMock([], [PygameRectMock((2, 0), "mask_rect2")], "mask2")
mask3 = PygameSurfaceMock([], [PygameRectMock((3, 0), "mask_rect3")], "mask3")
mask4 = PygameSurfaceMock([], [PygameRectMock((4, 0), "mask_rect4")], "mask4")
blit_rects1 = [PygameRectMock((1, 1), "blit_rect1.1"), PygameRectMock((1, 2), "blit_rect1.2")]
spr_image1 = PygameSurfaceMock(blit_rects1, [], "spr_img1")
blit_rects2 = [PygameRectMock((2, 1), "blit_rect2.1"), PygameRectMock((2, 2), "blit_rect2.2")]
spr_image2 = PygameSurfaceMock(blit_rects2, [], "spr_img2")
blit_rects3 = [PygameRectMock((3, 1), "blit_rect3.1"), PygameRectMock((3, 2), "blit_rect3.2")]
spr_image3 = PygameSurfaceMock(blit_rects3, [], "spr_img3")
blit_rects4 = [PygameRectMock((4, 1), "blit_rect4.1"), PygameRectMock((4, 2), "blit_rect4.2")]
spr_image4 = PygameSurfaceMock(blit_rects4, [], "spr_img4")
surfaces = [mask1, spr_image1, mask2, spr_image2, mask3, spr_image3, mask4, spr_image4, ]
rects = [PygameRectMock((1, 1), "rect1"), PygameRectMock((2, 2), "rect2"), PygameRectMock((3, 3), "rect3"),
PygameRectMock((4, 4), "rect4")]
pygame_mock = PygameMock(surfaces, rects, modules)
return draw_mock, mask1, mask2, mask3, mask4, pygame_mock, rects, spr_image1, spr_image2, spr_image3, \
spr_image4, sprite_sheet_surf
def _verify_pygame_module_mock_usage(self, actual, draw_mock, mask1, mask2, mask3, mask4, rects, spr_image1,
spr_image2, spr_image3, spr_image4, sprite_sheet_surf):
# verify that the right sprite images are returned
act = [(spr.image, spr.anchor, spr.gid) for spr in actual]
expected = [(spr_image1, [10, 10], 0),
(spr_image2, [0, 0], 1),
(spr_image3, [0, 0], 2),
(spr_image4, [0, 0], 3),
]
self.maxDiff = None
self.assertEqual(expected, act)
# verify that the right area is drawn to the sprites
self.assertIs(rects[0], spr_image1.method_calls[0][1][2])
self.assertIs(rects[1], spr_image2.method_calls[0][1][2])
self.assertIs(rects[2], spr_image3.method_calls[0][1][2])
self.assertIs(rects[3], spr_image4.method_calls[0][1][2])
# verify that the right points are drawn as polygon (point list is in local coordinates)
local_points_list = [[0, 0], [32, 0], [32, 32], [0, 32]]
self.assertEqual((PygameDrawModuleMock.polygon.__name__,
(mask1, (255, 255, 255, 255), local_points_list, 0)), draw_mock.method_calls[0])
self.assertEqual((PygameDrawModuleMock.polygon.__name__,
(mask2, (255, 255, 255, 255), local_points_list, 0)), draw_mock.method_calls[1])
self.assertEqual((PygameDrawModuleMock.polygon.__name__,
(mask3, (255, 255, 255, 255), local_points_list, 0)), draw_mock.method_calls[2])
self.assertEqual((PygameDrawModuleMock.polygon.__name__,
(mask4, (255, 255, 255, 255), local_points_list, 0)), draw_mock.method_calls[3])
# verify that the right area is used to blit the sprites image
self.assertEqual((PygameSurfaceMock.blit.__name__, (sprite_sheet_surf, (0, 0), rects[0], 0)),
spr_image1.method_calls[0])
self.assertEqual((PygameSurfaceMock.blit.__name__, (sprite_sheet_surf, (0, 0), rects[1], 0)),
spr_image2.method_calls[0])
self.assertEqual((PygameSurfaceMock.blit.__name__, (sprite_sheet_surf, (0, 0), rects[2], 0)),
spr_image3.method_calls[0])
self.assertEqual((PygameSurfaceMock.blit.__name__, (sprite_sheet_surf, (0, 0), rects[3], 0)),
spr_image4.method_calls[0])
[docs] def test_load_spritesheet_from_sdef(self):
# arrange
sdef = TestData.SDEF_GRID_2X2
image_file_info = FileInfoMock("spritesheet.png", True)
logger_mock = LoggerMock()
sut = SpritesheetLib10(logger_mock)
draw_mock, mask1, mask2, mask3, mask4, pygame_mock, rects, spr_image1, spr_image2, spr_image3, spr_image4, \
sprite_sheet_surf = self._create_pygame_module_mock()
# act
actual = sut.load_spritesheet_from_sdef(sdef, image_file_info, pygame_module=pygame_mock)
# verify
self._verify_pygame_module_mock_usage(actual, draw_mock, mask1, mask2, mask3, mask4, rects, spr_image1,
spr_image2, spr_image3, spr_image4, sprite_sheet_surf)
[docs] def test_load_spritesheet_from_sdef_and_surface(self):
# arrange
sdef = TestData.SDEF_GRID_2X2
logger_mock = LoggerMock()
sut = SpritesheetLib10(logger_mock)
draw_mock, mask1, mask2, mask3, mask4, pygame_mock, rects, spr_image1, spr_image2, spr_image3, spr_image4, \
sprite_sheet_surf = self._create_pygame_module_mock()
# act
actual = sut.load_spritesheet_from_sdef_and_surface(sdef, sprite_sheet_surf, pygame_module=pygame_mock)
# verify
self._verify_pygame_module_mock_usage(actual, draw_mock, mask1, mask2, mask3, mask4, rects, spr_image1,
spr_image2, spr_image3, spr_image4, sprite_sheet_surf)
[docs] def test_get_image_name_from_sdef_name(self):
# arrange
logger_mock = LoggerMock()
sut = SpritesheetLib10(logger_mock)
image_file_name = "bla.png"
sdef_file_name = image_file_name + ".grr"
# act
actual = sut.get_image_name_from_sdef_name(sdef_file_name)
# verify
self.assertEqual(image_file_name, actual)
[docs] def test_get_image_name_from_sdef_name_missing_extension(self):
# arrange
logger_mock = LoggerMock()
sut = SpritesheetLib10(logger_mock)
image_file_name = "bla"
sdef_file_name = image_file_name + ".grr"
# act / verify
self.assertRaises(ValueError, sut.get_image_name_from_sdef_name, sdef_file_name)
[docs] def test_get_image_name_from_sdef(self):
# arrange
logger_mock = LoggerMock()
sut = SpritesheetLib10(logger_mock)
image_file_name = "sdef_name.png"
sdef = sut.clone_sprite_definition(TestData.SDEF_GRID_2X2)
sdef_file_name = image_file_name + ".sdef"
sdef[SpritesheetLib10.ELEMENTS.FILENAME] = sdef_file_name
# act
actual = sut.get_image_name_from_sdef(sdef)
# verify
self.assertEqual(image_file_name, actual)
[docs] def test_get_image_name_from_sdef_missing_extension(self):
# arrange
logger_mock = LoggerMock()
sut = SpritesheetLib10(logger_mock)
image_file_name = "bla"
sdef = sut.clone_sprite_definition(TestData.SDEF_GRID_2X2)
sdef_file_name = image_file_name + ".sdef"
sdef[SpritesheetLib10.ELEMENTS.FILENAME] = sdef_file_name
# act / verify
self.assertRaises(ValueError, sut.get_image_name_from_sdef, sdef)
[docs]class TestSpritesheetLibSaveToDisk(unittest.TestCase):
[docs] def setUp(self):
self.logger_mock = LoggerMock()
self.file_name_sdef = "temp_out.png.sdef"
self.file_name_image = self.file_name_sdef
[docs] def test_image_is_written_to_disk(self):
# arrange
img_fi = FileInfoMock(self.file_name_sdef, False)
import pygame
img = pygame.Surface((10, 10))
sut = mut.SpritesheetLib10(self.logger_mock)
pyg_image = PygameImageModuleMock([])
pyg_mod = PygameMock([], [], {PygameMock.IMAGE_MODULE_NAME: pyg_image})
# act
sut.save_image_to_disk(img, img_fi, pygame_module=pyg_mod)
# verify
self.assertEqual(0, len(img_fi.method_calls))
self.assertEqual((PygameImageModuleMock.save.__name__, (img, self.file_name_image)), pyg_image.method_calls[0])
[docs] def test_image_is_deleted_if_exists_before_written_to_disk(self):
# arrange
img_fi = FileInfoMock(self.file_name_sdef, True)
import pygame
img = pygame.Surface((10, 10))
sut = mut.SpritesheetLib10(self.logger_mock)
pyg_image = PygameImageModuleMock([])
pyg_mod = PygameMock([], [], {PygameMock.IMAGE_MODULE_NAME: pyg_image})
# act
sut.save_image_to_disk(img, img_fi, pygame_module=pyg_mod)
# verify
# self.assertTrue(img_fi.exists)
# self.assertTrue(os.path.getsize(img_fi.name) > 0)
self.assertEqual((FileInfoMock.delete.__name__, ()), img_fi.method_calls[0])
self.assertEqual((PygameImageModuleMock.save.__name__, (img, self.file_name_image)), pyg_image.method_calls[0])
[docs] def test_sdef_is_written_to_disk(self):
# arrange
fi = FileInfoMock(self.file_name_image, False)
sut = mut.SpritesheetLib10(self.logger_mock)
sdef = TestData.SDEF_GRID_2X2
# act
sut.save_sprite_definition_to_disk(sdef, fi)
# verify
# noinspection PyTypeChecker
self.assertTrue(len(fi.getvalue()) > 0)
[docs] def test_sdef_is_deleted_before_written_to_disk(self):
# arrange
fi = FileInfoMock(self.file_name_image, True)
sut = mut.SpritesheetLib10(self.logger_mock)
sdef = TestData.SDEF_GRID_2X2
# act
sut.save_sprite_definition_to_disk(sdef, fi)
# verify
# noinspection PyTypeChecker
self.assertTrue(len(fi.getvalue()) > 0)
self.assertEqual((FileInfoMock.delete.__name__, ()), fi.method_calls[0])
self.assertEqual((FileInfoMock.open.__name__, (mut.FileMode.WriteBinary, )), fi.method_calls[1])
# noinspection PyDocstring
[docs]class PygameImageModuleMock(object):
"""
The pygame image module mock.
:param images: The images if loads. Must be provided in the order they are needed.
"""
def __init__(self, images):
self.images = list(images)
self.method_calls = [] # [(method_name, (args)), ]
[docs] def load(self, filename):
self.method_calls.append((PygameImageModuleMock.load.__name__, (filename,)))
return self.images.pop(0)
[docs] def save(self, surface, filename):
self.method_calls.append((PygameImageModuleMock.save.__name__, (surface, filename,)))
[docs]class TestPygameImageModuleMock(unittest.TestCase):
[docs] def test_load(self):
# arrange
sut = PygameImageModuleMock([1, 2, 3])
# act
actual1 = sut.load(345345)
actual2 = sut.load(1234)
# verify
self.assertEqual(1, actual1)
self.assertEqual(2, actual2)
self.assertEqual((PygameImageModuleMock.load.__name__, (345345,)), sut.method_calls[0])
self.assertEqual((PygameImageModuleMock.load.__name__, (1234,)), sut.method_calls[1])
[docs] def test_save(self):
# arrange
sut = PygameImageModuleMock([])
surf = object()
image_name = "whatever"
# act
sut.save(surf, image_name)
# verify
self.assertEqual((PygameImageModuleMock.save.__name__, (surf, image_name)), sut.method_calls[0])
# noinspection PyDocstring
[docs]class PygameDrawModuleMock(object):
"""
The pygame draw module mock.
:param rects: The rects returned by the draw methods. They have to be in the order they are needed.
"""
def __init__(self, rects):
self.method_calls = [] # [(method_name, (args)), ]
self.rects = list(rects)
[docs] def polygon(self, surface, color, pointlist, width=0):
self.method_calls.append((PygameDrawModuleMock.polygon.__name__, (surface, color, pointlist, width)))
return self.rects.pop(0)
[docs]class TestPygameDrawModuleMock(unittest.TestCase):
[docs] def test_polygon(self):
# arrange
sut = PygameDrawModuleMock([1, 2, 3])
surf = 1
color = "black"
pointlist = "points"
width = 3
# act
actual1 = sut.polygon(surf, color, pointlist, width)
actual2 = sut.polygon(surf, color, pointlist)
# verify
self.assertEqual(1, actual1)
self.assertEqual(2, actual2)
self.assertEqual((PygameDrawModuleMock.polygon.__name__, (surf, color, pointlist, width,)), sut.method_calls[0])
self.assertEqual((PygameDrawModuleMock.polygon.__name__, (surf, color, pointlist, 0)), sut.method_calls[1])
# noinspection PyDocstring
[docs]class PygameSurfaceMock(object):
"""
The pygame surface mock.
:param blit_rects: The rects returned by the blit method.
:param fill_rects: The rects returned by the fill method.
:param name: The name of the surface, more of an identifier, makes it easier to match the correct surface mocks.
"""
def __init__(self, blit_rects, fill_rects, name):
self.method_calls = [] # [(method_name, (args)), ]
self.blit_rects = list(blit_rects)
self.fill_rects = list(fill_rects)
self.name = name
[docs] def blit(self, source, destination, area=None, special_flags=0):
self.method_calls.append((PygameSurfaceMock.blit.__name__, (source, destination, area, special_flags)))
return self.blit_rects.pop(0)
[docs] def fill(self, color, rect=None, special_flags=0):
self.method_calls.append((PygameSurfaceMock.fill.__name__, (color, rect, special_flags)))
return self.fill_rects.pop(0)
def __str__(self):
return "<{0}.{1}['{2}']>".format(self.__module__, self.__class__.__name__, self.name)
def __repr__(self):
return str(self)
[docs]class TestPygameSurfaceMock(unittest.TestCase):
[docs] def test_name_str(self):
# arrange
name = "mock1"
sut = PygameSurfaceMock([], [], name)
# act
actual = repr(sut)
# verify
expected = "<{0}.{1}['{2}']>".format(PygameSurfaceMock.__module__, PygameSurfaceMock.__name__, name)
self.assertEqual(expected, actual)
[docs] def test_name_string(self):
# arrange
name = "mock1"
sut = PygameSurfaceMock([], [], name)
# act
actual = str(sut)
# verify
expected = "<{0}.{1}['{2}']>".format(PygameSurfaceMock.__module__, PygameSurfaceMock.__name__, name)
self.assertEqual(expected, actual)
[docs] def test_blit(self):
# arrange
sut = PygameSurfaceMock([1, 2, 3], [10, 11, 12], "mock1")
source = "source"
destination = "destination"
area = "area"
special_flags = 42
# act
actual1 = sut.blit(source, destination, area, special_flags)
actual2 = sut.blit(source, destination)
# verify
self.assertEqual(1, actual1)
self.assertEqual(2, actual2)
self.assertEqual((PygameSurfaceMock.blit.__name__, (source, destination, area, special_flags)),
sut.method_calls[0])
self.assertEqual((PygameSurfaceMock.blit.__name__, (source, destination, None, 0)), sut.method_calls[1])
[docs] def test_fill(self):
# arrange
sut = PygameSurfaceMock([], [1, 2, 3], "mock1")
color = 33
rect = "R"
special_flags = 42
# act
actual_rect = sut.fill(color, rect, special_flags)
# verify
self.assertEqual(1, actual_rect)
self.assertEqual((PygameSurfaceMock.fill.__name__, (color, rect, special_flags)), sut.method_calls[0])
# noinspection PyDocstring
[docs]class PygameRectMock(object):
"""
The pygame rect mock.
:param size: The size of the rect.
:param name: The name of the rect, makes matching rect mock instances easier.
"""
def __init__(self, size, name):
self.property_calls = [] # [(prop_name, 'set'|'get', args), ]
self._size = size
self.name = name
@property
def size(self):
self.property_calls.append(("size", "get", tuple()))
return self._size
@size.setter
def size(self, value):
self.property_calls.append(("size", "set", tuple(value)))
self._size = value
def __str__(self):
return "<{0}.{1}['{2}']>".format(self.__module__, self.__class__.__name__, self.name)
def __repr__(self):
return str(self)
[docs]class TestPygameRectMock(unittest.TestCase):
[docs] def test_name_str(self):
# arrange
name = "mock1"
sut = PygameRectMock([], name)
# act
actual = repr(sut)
# verify
expected = "<{0}.{1}['{2}']>".format(PygameRectMock.__module__, PygameRectMock.__name__, name)
self.assertEqual(expected, actual)
[docs] def test_name_string(self):
# arrange
name = "mock1"
sut = PygameRectMock([], name)
# act
actual = str(sut)
# verify
expected = "<{0}.{1}['{2}']>".format(PygameRectMock.__module__, PygameRectMock.__name__, name)
self.assertEqual(expected, actual)
[docs] def test_get_size_property(self):
# arrange
w = 14
h = 42
sut = PygameRectMock((w, h), "rect_mock1")
# act
actual = sut.size
# verify
self.assertEqual((w, h), actual)
self.assertEqual(("size", "get", tuple()), sut.property_calls[0])
[docs] def test_set_size_property(self):
# arrange
w = 14
h = 42
sut = PygameRectMock((1, 2), "rect_mock1")
# act
sut.size = (w, h)
actual = sut.size
# verify
self.assertEqual((w, h), actual)
self.assertEqual(("size", "set", tuple((w, h))), sut.property_calls[0])
# noinspection PyDocstring
[docs]class PygameMock(object):
"""
The pygame module mock.
:param surfaces: The surfaces that should be returned by calls to pygame.Surface().
:param rects: The rects that should be returned by calls to pygame.Rect().
:param modules: The modules present as a dictionary, e.g. {PygameMock.IMAGE_MODULE_NAME: image_module_mock}
"""
IMAGE_MODULE_NAME = "image"
DRAW_MODULE_NAME = "draw"
# constants
BLEND_RGBA_MULT = 1
SRCALPHA = 2
def __init__(self, surfaces, rects, modules=None):
if not modules:
modules = {}
self.method_calls = [] # [(method_name, (args)), ]
self.property_calls = [] # [(property_name, 'set'|'get', args), ]
self.surfaces = list(surfaces)
self.rects = list(rects)
self._image = None
if self.IMAGE_MODULE_NAME in modules:
self._image = modules[self.IMAGE_MODULE_NAME]
self._draw = None
if self.DRAW_MODULE_NAME in modules:
self._draw = modules[self.DRAW_MODULE_NAME]
@property
def image(self):
self.property_calls.append((self.IMAGE_MODULE_NAME, "get", tuple()))
return self._image
@property
def draw(self):
self.property_calls.append((self.DRAW_MODULE_NAME, "get", tuple()))
return self._draw
# noinspection PyPep8Naming
[docs] def Surface(self, size, flags=0, depth=0, masks=None):
# surf = PygameSurfaceMock([], [], "Surface" + str(len(self.method_calls)))
# self.method_calls.append((PygameMock.Surface.__name__, (size, flags, depth, masks), surf))
# return surf
self.method_calls.append((PygameMock.Surface.__name__, (size, flags, depth, masks)))
return self.surfaces.pop(0)
# noinspection PyPep8Naming
[docs] def Rect(self, left, top=None, width=None, height=None):
self.method_calls.append((PygameMock.Rect.__name__, (left, top, width, height)))
return self.rects.pop(0)
[docs]class TestPygameMock(unittest.TestCase):
[docs] def test_image_module_retrieval(self):
# arrange
images = ["spritesheet"]
# draw_rects = []
image_module_mock = PygameImageModuleMock(images)
modules = {PygameMock.IMAGE_MODULE_NAME: image_module_mock, }
surfaces = []
rects = []
sut = PygameMock(surfaces, rects, modules)
# act
actual_image_module = sut.image
# verify
self.assertIs(image_module_mock, actual_image_module)
self.assertEqual(("image", "get", tuple()), sut.property_calls[0])
[docs] def test_draw_module_retrieval(self):
# arrange
draw_rects = ["rects"]
draw_module_mock = PygameDrawModuleMock(draw_rects)
modules = {PygameMock.DRAW_MODULE_NAME: draw_module_mock}
surfaces = []
rects = []
sut = PygameMock(surfaces, rects, modules)
# act
actual_draw_module = sut.draw
# verify
self.assertIs(draw_module_mock, actual_draw_module)
self.assertEqual(("draw", "get", tuple()), sut.property_calls[0])
[docs] def test_surface_creation(self):
# arrange
blit_rects = []
fill_rects = []
surf1 = PygameSurfaceMock(blit_rects, fill_rects, "surf1")
surf2 = PygameSurfaceMock(blit_rects, fill_rects, "surf2")
surfaces = [surf1, surf2]
rects = []
sut = PygameMock(surfaces, rects)
size = (2, 3)
# act
actual = sut.Surface(size)
actual2 = sut.Surface(size)
# verify
self.assertIs(surf1, actual)
self.assertIs(surf2, actual2)
self.assertEqual((PygameMock.Surface.__name__, (size, 0, 0, None)), sut.method_calls[0])
[docs] def test_rect_creation(self):
# arrange
surfaces = []
size = (2, 3)
rect1 = PygameRectMock(size, "rect_mock1")
rect2 = PygameRectMock(size, "rect_mock2")
rects = [rect1, rect2]
sut = PygameMock(surfaces, rects)
x = 1
y = 2
w = 5
h = 7
# act
actual = sut.Rect(x, y, w, h)
actual2 = sut.Rect(x, y, w, h)
# verify
self.assertIs(rect1, actual)
self.assertIs(rect2, actual2)
self.assertEqual((PygameMock.Rect.__name__, (x, y, w, h)), sut.method_calls[0])
[docs]class TestSpritesList(unittest.TestCase):
[docs] def setUp(self):
self.sprites = mut.SpritesList()
gid = 0
for y in range(4):
for x in range(4):
properties = {SpritesheetLib10.PROPERTIES.COLUMN: x, SpritesheetLib10.PROPERTIES.ROW: y}
self.sprites.append(mut.Sprite(PygameSurfaceMock([], [], str(gid)), [], gid, properties))
gid += 1
[docs] def test_create_empty_instance(self):
# act
actual = mut.SpritesList()
# verify
self.assertEqual(0, len(actual))
[docs] def test_create_instance_with_entries(self):
# arrange
data = [1, 2, 3, 4]
# act
actual = mut.SpritesList(data)
# verify
self.assertEqual(data, actual)
[docs] def test_get_cols(self):
# arrange
expected = [
[self.sprites[0], self.sprites[4], self.sprites[8], self.sprites[12]],
[self.sprites[1], self.sprites[5], self.sprites[9], self.sprites[13]],
[self.sprites[2], self.sprites[6], self.sprites[10], self.sprites[14]],
[self.sprites[3], self.sprites[7], self.sprites[11], self.sprites[15]],
]
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act
cols = self.sprites.get_columns()
# verify
self.maxDiff = None
self.assertListEqual(expected, cols)
[docs] def test_get_cols_with_gap(self):
# arrange
expected = [
[self.sprites[0], self.sprites[4], self.sprites[8], self.sprites[12]],
[self.sprites[5], self.sprites[9], self.sprites[13]],
[self.sprites[2], self.sprites[10], self.sprites[14]],
[self.sprites[3], self.sprites[7], self.sprites[11], self.sprites[15]],
]
self.sprites[1].properties = {}
self.sprites[6].properties = {}
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act
cols = self.sprites.get_columns()
# verify
self.maxDiff = None
self.assertEqual(expected, cols)
[docs] def test_get_cols_fail_while_row_prop_is_missing(self):
# arrange
del self.sprites[5].properties[SpritesheetLib10.PROPERTIES.ROW]
# act / verify
self.assertRaises(mut.SpriteListException, self.sprites.get_columns)
[docs] def test_get_rows(self):
# arrange
expected = [
[self.sprites[0], self.sprites[1], self.sprites[2], self.sprites[3]],
[self.sprites[4], self.sprites[5], self.sprites[6], self.sprites[7]],
[self.sprites[8], self.sprites[9], self.sprites[10], self.sprites[11]],
[self.sprites[12], self.sprites[13], self.sprites[14], self.sprites[15]],
]
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act
rows = self.sprites.get_rows()
# verify
self.assertEqual(expected, rows)
[docs] def test_get_row_with_gap(self):
# arrange
expected = [
[self.sprites[0], self.sprites[2], self.sprites[3]],
[self.sprites[4], self.sprites[5], self.sprites[7]],
[self.sprites[8], self.sprites[9], self.sprites[10], self.sprites[11]],
[self.sprites[12], self.sprites[13], self.sprites[14], self.sprites[15]],
]
self.sprites[1].properties = {}
self.sprites[6].properties = {}
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act
rows = self.sprites.get_rows()
# verify
self.assertEqual(expected, rows)
[docs] def test_get_rows_fail_while_col_prop_is_missing(self):
# arrange
del self.sprites[5].properties[SpritesheetLib10.PROPERTIES.COLUMN]
# act / verify
self.assertRaises(mut.SpriteListException, self.sprites.get_rows)
[docs] def test_get_grouped_by_property(self):
# arrange
property_name = 'count'
self.sprites[0].properties[property_name] = 1
self.sprites[1].properties[property_name] = 2
self.sprites[2].properties[property_name] = 2
self.sprites[3].properties[property_name] = 3
self.sprites[4].properties[property_name] = 3
self.sprites[5].properties[property_name] = 3
self.sprites[6].properties[property_name] = 4
self.sprites[7].properties[property_name] = 4
self.sprites[8].properties[property_name] = 4
self.sprites[9].properties[property_name] = 4
self.sprites[10].properties[property_name] = 5
self.sprites[11].properties[property_name] = 5
self.sprites[12].properties[property_name] = 5
self.sprites[13].properties[property_name] = 5
self.sprites[14].properties[property_name] = 5
expected = {
1: [self.sprites[0], ],
2: [self.sprites[1], self.sprites[2], ],
3: [self.sprites[3], self.sprites[4], self.sprites[5], ],
4: [self.sprites[6], self.sprites[7], self.sprites[8], self.sprites[9], ],
5: [self.sprites[10], self.sprites[11], self.sprites[12], self.sprites[13], self.sprites[14], ],
None: [self.sprites[15], ],
}
for k, v in expected.items():
v.sort(key=lambda spr: id(spr))
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act
actual = self.sprites.get_grouped_by_property(property_name, lambda spr: id(spr))
# verify
self.maxDiff = None
self.assertDictEqual(expected, actual)
def _setup_facing_and_action_properties(self):
self.sprites[0].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'up'
self.sprites[0].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'still'
self.sprites[1].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'up'
self.sprites[1].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[2].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'up'
self.sprites[2].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[3].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'up'
self.sprites[3].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[4].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'left'
self.sprites[4].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'still'
self.sprites[5].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'left'
self.sprites[5].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[6].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'left'
self.sprites[6].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[7].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'left'
self.sprites[7].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[8].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'r'
self.sprites[8].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'still'
self.sprites[9].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'r'
self.sprites[9].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[10].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'r'
self.sprites[10].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[11].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'r'
self.sprites[11].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[12].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'd'
self.sprites[12].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'still'
self.sprites[13].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'd'
self.sprites[13].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[14].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'd'
self.sprites[14].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
self.sprites[15].properties[mut.SpritesheetLib10.PROPERTIES.FACING] = 'd'
self.sprites[15].properties[mut.SpritesheetLib10.PROPERTIES.ACTION] = 'walk'
[docs] def test_get_grouped_by_facing_and_action(self):
# arrange
self._setup_facing_and_action_properties()
expected = {
'up': {'still': [self.sprites[0]], 'walk': [self.sprites[1], self.sprites[2], self.sprites[3], ]},
'r': {'still': [self.sprites[8]], 'walk': [self.sprites[9], self.sprites[10], self.sprites[11], ]},
'd': {'still': [self.sprites[12]], 'walk': [self.sprites[13], self.sprites[14], self.sprites[15], ]},
'left': {'still': [self.sprites[4]], 'walk': [self.sprites[5], self.sprites[6], self.sprites[7], ]},
}
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act
actual = self.sprites.get_grouped_by_facing_and_action()
# verify
self.maxDiff = None
self.assertDictEqual(expected, actual)
[docs] def test_get_grouped_by_facing_and_action_some_missing(self):
# arrange
self._setup_facing_and_action_properties()
del self.sprites[0].properties[mut.SpritesheetLib10.PROPERTIES.FACING]
del self.sprites[0].properties[mut.SpritesheetLib10.PROPERTIES.ACTION]
del self.sprites[1].properties[mut.SpritesheetLib10.PROPERTIES.FACING]
expected = {
'up': {'walk': [self.sprites[2], self.sprites[3], ]},
'r': {'still': [self.sprites[8]], 'walk': [self.sprites[9], self.sprites[10], self.sprites[11], ]},
'd': {'still': [self.sprites[12]], 'walk': [self.sprites[13], self.sprites[14], self.sprites[15], ]},
'left': {'still': [self.sprites[4]], 'walk': [self.sprites[5], self.sprites[6], self.sprites[7], ]},
None: {None: [self.sprites[0]], 'walk': [self.sprites[1]]},
}
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act
actual = self.sprites.get_grouped_by_facing_and_action()
# verify
self.maxDiff = None
self.assertDictEqual(expected, actual)
[docs] def test_get_grouped_by_facing_and_action_fails_missing_action(self):
# arrange
self._setup_facing_and_action_properties()
del self.sprites[0].properties[mut.SpritesheetLib10.PROPERTIES.ACTION]
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act / verify
self.assertRaises(mut.SpriteListException, self.sprites.get_grouped_by_facing_and_action)
[docs] def test_get_grouped_by_action_and_facing(self):
# arrange
self._setup_facing_and_action_properties()
expected = {
'walk': {'up': [self.sprites[1], self.sprites[2], self.sprites[3], ],
'r': [self.sprites[9], self.sprites[10], self.sprites[11], ],
'd': [self.sprites[13], self.sprites[14], self.sprites[15], ],
'left': [self.sprites[5], self.sprites[6], self.sprites[7], ]},
'still': {'up': [self.sprites[0], ],
'r': [self.sprites[8], ],
'd': [self.sprites[12], ],
'left': [self.sprites[4], ]},
}
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act
actual = self.sprites.get_grouped_by_action_and_facing()
# verify
self.maxDiff = None
self.assertDictEqual(expected, actual)
[docs] def test_get_grouped_by_action_and_facing_some_missing(self):
# arrange
self._setup_facing_and_action_properties()
del self.sprites[0].properties[mut.SpritesheetLib10.PROPERTIES.FACING]
del self.sprites[0].properties[mut.SpritesheetLib10.PROPERTIES.ACTION]
del self.sprites[1].properties[mut.SpritesheetLib10.PROPERTIES.ACTION]
expected = {
'walk': {'up': [self.sprites[2], self.sprites[3], ],
'r': [self.sprites[9], self.sprites[10], self.sprites[11], ],
'd': [self.sprites[13], self.sprites[14], self.sprites[15], ],
'left': [self.sprites[5], self.sprites[6], self.sprites[7], ]},
'still': {'r': [self.sprites[8], ],
'd': [self.sprites[12], ],
'left': [self.sprites[4], ]},
None: {None: [self.sprites[0]], 'up': [self.sprites[1]], }
}
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act
actual = self.sprites.get_grouped_by_action_and_facing()
# verify
self.maxDiff = None
self.assertDictEqual(expected, actual)
[docs] def test_get_grouped_by_action_and_facing_fails_missing_facing(self):
# arrange
self._setup_facing_and_action_properties()
del self.sprites[0].properties[mut.SpritesheetLib10.PROPERTIES.FACING]
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act / verify
self.assertRaises(mut.SpriteListException, self.sprites.get_grouped_by_action_and_facing)
[docs] def test_get_gid_slice(self):
# arrange
expected = [self.sprites[4],
self.sprites[5],
self.sprites[6],
self.sprites[7],
self.sprites[8],
]
# random sprite order to ensure right order in the result
random.shuffle(self.sprites)
# act
actual = self.sprites.get_gid_slice(4, 8)
# verify
self.assertEqual(expected, actual)
@ddtd.use_data_driven_testing_decorators
[docs]class TestSpritesheetLib10UpdateProperties(unittest.TestCase):
[docs] def setUp(self):
self.logger_mock = LoggerMock()
self.data = SpritesheetLib10(self.logger_mock).clone_sprite_definition(TestData.SDEF_GRID_2X2)
[docs] def test_update_properties_need_key_mode(self):
# arrange
properties = {1: 'bla'}
sut = SpritesheetLib10(self.logger_mock)
# act
with self.assertRaises(KeyError) as cm:
sut.update_sprite_properties(TestData.SDEF_GRID_2X2, properties)
# verify
message = str(cm.exception)
self.assertTrue(V1PROPERTIES.MODE in message)
@ddtd.test_case(V1PROPERTIES.MODE_UPDATE, test_name="mode_update")
@ddtd.test_case(V1PROPERTIES.MODE_UPDATE_STRICT, test_name="mode_update_strict")
@ddtd.test_case(V1PROPERTIES.MODE_EXTEND, test_name="mode_extend")
@ddtd.test_case(V1PROPERTIES.MODE_EXTEND_STRICT, test_name="mode_extend_strict")
def test_properties_mode_only_accepts_valid_mode_value(self, mode):
# arrange
self._add_bla_bla_property()
properties = {
V1PROPERTIES.MODE: mode,
0: {'bla': 'zzz', 'BLU': 'blu'},
1: {'bla': 'zzz'},
2: {'bla': 'zzz'},
3: {'bla': 'zzz'},
}
sut = SpritesheetLib10(self.logger_mock)
# act
sut.update_sprite_properties(self.data, properties)
[docs] def test_properties_mode_wrong_value_raises_value_error(self):
# arrange
properties = {
V1PROPERTIES.MODE: 'wrong_value',
}
sut = SpritesheetLib10(self.logger_mock)
# act / verify
self.assertRaises(ValueError, sut.update_sprite_properties, TestData.SDEF_GRID_2X2, properties)
def _add_bla_bla_property(self, value='bla'):
for sprite in self.data[V1ELEMENTS.SPRITES]:
sprite[V1ELEMENTS.PROPERTIES] = {'bla': value}
[docs] def test_mode_update_strict_missing_key_raise(self):
# arrange
self._add_bla_bla_property()
new_value = 'zzz'
properties = {
V1PROPERTIES.MODE: V1PROPERTIES.MODE_UPDATE_STRICT,
0: {'bla': new_value, 'new': 'new_val'},
# 1: {'bla': new_value}, missing
# 2: {'bla': new_value}, missing
# 3: {'bla': new_value}, missing
}
sut = SpritesheetLib10(self.logger_mock)
# act / verify
self.assertRaises(KeyError, sut.update_sprite_properties, self.data, properties)
[docs] def test_mode_update_strict_no_missing_key(self):
# arrange
self._add_bla_bla_property()
new_value = 'zzz'
bla = 'bla'
properties = {
V1PROPERTIES.MODE: V1PROPERTIES.MODE_UPDATE_STRICT,
0: {bla: new_value, 'new': 'new-val'},
1: {bla: new_value},
2: {bla: new_value},
3: {bla: new_value},
}
sut = SpritesheetLib10(self.logger_mock)
expected = sut.clone_sprite_definition(self.data)
expected[V1ELEMENTS.SPRITES][0][V1ELEMENTS.PROPERTIES][bla] = new_value
expected[V1ELEMENTS.SPRITES][0][V1ELEMENTS.PROPERTIES]['new'] = 'new-val'
expected[V1ELEMENTS.SPRITES][1][V1ELEMENTS.PROPERTIES][bla] = new_value
expected[V1ELEMENTS.SPRITES][2][V1ELEMENTS.PROPERTIES][bla] = new_value
expected[V1ELEMENTS.SPRITES][3][V1ELEMENTS.PROPERTIES][bla] = new_value
# act
sut.update_sprite_properties(self.data, properties)
# verify
self.maxDiff = None
self.assertDictEqual(expected, self.data)
[docs] def test_mode_update_missing_key_does_not_raise(self):
# arrange
# sprite definition
self._add_bla_bla_property()
self.data[V1ELEMENTS.SPRITES][0][V1ELEMENTS.PROPERTIES]['blu'] = 'xxx'
# properties
properties = {
V1PROPERTIES.MODE: V1PROPERTIES.MODE_UPDATE,
0: {'bla': 'zzz', 'ble': 'ble'},
}
sut = SpritesheetLib10(self.logger_mock)
expected = sut.clone_sprite_definition(self.data)
expected[V1ELEMENTS.SPRITES][0][V1ELEMENTS.PROPERTIES]['bla'] = 'zzz'
expected[V1ELEMENTS.SPRITES][0][V1ELEMENTS.PROPERTIES]['ble'] = 'ble'
# act
sut.update_sprite_properties(self.data, properties)
# verify
self.maxDiff = None
self.assertDictEqual(expected, self.data)
[docs] def test_mode_extend(self):
# arrange
self._add_bla_bla_property()
properties = {
V1PROPERTIES.MODE: V1PROPERTIES.MODE_EXTEND,
0: {'bla': 'zzz', 'blu': 'xxx'},
}
sut = SpritesheetLib10(self.logger_mock)
expected = sut.clone_sprite_definition(self.data)
expected[V1ELEMENTS.SPRITES][0][V1ELEMENTS.PROPERTIES][u'blu'] = u'xxx'
# act
sut.update_sprite_properties(self.data, properties)
# verify
self.maxDiff = None
self.assertDictEqual(expected, self.data)
[docs] def test_mode_extend_strict_ok(self):
# arrange
self._add_bla_bla_property()
properties = {
V1PROPERTIES.MODE: V1PROPERTIES.MODE_EXTEND_STRICT,
0: {'bla': 'zzz', 'blu': 'xxx'},
1: {'bla': 'zzz', 'blu': 'xxx'},
2: {'bla': 'zzz', 'blu': 'xxx'},
3: {'bla': 'zzz', 'blu': 'xxx'},
}
sut = SpritesheetLib10(self.logger_mock)
expected = sut.clone_sprite_definition(self.data)
expected[V1ELEMENTS.SPRITES][0][V1ELEMENTS.PROPERTIES][u'blu'] = u'xxx'
expected[V1ELEMENTS.SPRITES][1][V1ELEMENTS.PROPERTIES][u'blu'] = u'xxx'
expected[V1ELEMENTS.SPRITES][2][V1ELEMENTS.PROPERTIES][u'blu'] = u'xxx'
expected[V1ELEMENTS.SPRITES][3][V1ELEMENTS.PROPERTIES][u'blu'] = u'xxx'
# act
sut.update_sprite_properties(self.data, properties)
# verify
self.maxDiff = None
self.assertDictEqual(expected, self.data)
[docs] def test_mode_extend_strict_raises_on_missing_gid(self):
# arrange
self._add_bla_bla_property()
properties = {
V1PROPERTIES.MODE: V1PROPERTIES.MODE_EXTEND_STRICT,
0: {'bla': 'zzz', 'blu': 'xxx'},
# 1: {'bla': 'zzz', 'blu': 'xxx'}, missing gid!
2: {'bla': 'zzz', 'blu': 'xxx'},
3: {'bla': 'zzz', 'blu': 'xxx'},
}
sut = SpritesheetLib10(self.logger_mock)
# act / verify
self.assertRaises(KeyError, sut.update_sprite_properties, self.data, properties)
if __name__ == '__main__': # pragma: no cover
unittest.main()