Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 24 additions & 23 deletions tests/coilsnake_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,41 +3,42 @@

import os
from PIL import Image, ImageChops
from nose.tools import assert_is_none
from nose.tools.trivial import eq_
from unittest import TestCase


TEST_DATA_DIR = os.path.join(os.path.dirname(__file__), "test_data")
TEST_IMAGE_DIR = os.path.join(TEST_DATA_DIR, "images")


def assert_files_equal(expected, result):
for i in zip_longest(iter(expected), iter(result)):
eq_(i[0], i[1])
def earthbound_rom_available():
return os.path.exists(os.path.join(TEST_DATA_DIR, "roms", "real_EarthBound.smc"))


def assert_images_equal(expected, result):
assert_is_none(ImageChops.difference(expected, result).getbbox())


class BaseTestCase(object):
class BaseTestCase(TestCase):
def test_baseline(self):
pass

def assert_files_equal(self, expected, result):
for i in zip_longest(iter(expected), iter(result)):
self.assertEqual(i[0], i[1])


def assert_images_equal(self, expected, result):
self.assertIsNone(ImageChops.difference(expected, result).getbbox())

class TemporaryWritableFileTestCase(object):
def setup(self):
class TemporaryWritableFileTestCase(TestCase):
def setUp(self):
self.temporary_wo_file = tempfile.NamedTemporaryFile(mode='w', delete=False)
self.temporary_wo_file_name = self.temporary_wo_file.name

def teardown(self):
def tearDown(self):
if not self.temporary_wo_file.closed:
self.temporary_wo_file.close()
os.remove(self.temporary_wo_file_name)


class TilesetImageTestCase(object):
def setup(self):
class TilesetImageTestCase(TestCase):
def setUp(self):
self.tile_image_01_fp = open(os.path.join(TEST_IMAGE_DIR, "tile_image_01.png"), 'rb')
self.tile_image_01_img = Image.open(self.tile_image_01_fp)
self.tile_8x8_2bpp_fp = open(os.path.join(TEST_IMAGE_DIR, "tile_8x8_2bpp.png"), 'rb')
Expand All @@ -49,7 +50,7 @@ def setup(self):
self.tile_8x16_4bpp_fp = open(os.path.join(TEST_IMAGE_DIR, "tile_8x16_4bpp.png"), 'rb')
self.tile_8x16_4bpp_img = Image.open(self.tile_8x16_4bpp_fp)

def teardown(self):
def tearDown(self):
self.tile_image_01_fp.close()
del self.tile_image_01_img
self.tile_8x8_2bpp_fp.close()
Expand All @@ -62,25 +63,25 @@ def teardown(self):
del self.tile_8x16_4bpp_img


class SpriteGroupTestCase(object):
def setup(self):
class SpriteGroupTestCase(TestCase):
def setUp(self):
self.spritegroup_1_f = open(os.path.join(TEST_IMAGE_DIR, "spritegroup_16x24_1.png"), 'rb')
self.spritegroup_1_img = Image.open(self.spritegroup_1_f)
self.spritegroup_2_f = open(os.path.join(TEST_IMAGE_DIR, "spritegroup_16x24_2.png"), 'rb')
self.spritegroup_2_img = Image.open(self.spritegroup_2_f)

def teardown(self):
def tearDown(self):
self.spritegroup_1_f.close()
del self.spritegroup_1_img
self.spritegroup_2_f.close()
del self.spritegroup_2_img


class SwirlTestCase(object):
def setup(self):
class SwirlTestCase(TestCase):
def setUp(self):
self.swirl_1_f = open(os.path.join(TEST_IMAGE_DIR, "swirl_1.png"), 'rb')
self.swirl_1_img = Image.open(self.swirl_1_f)

def teardown(self):
def tearDown(self):
self.swirl_1_f.close()
del self.swirl_1_img
del self.swirl_1_img
371 changes: 187 additions & 184 deletions tests/model/common/test_blocks.py

Large diffs are not rendered by default.

45 changes: 23 additions & 22 deletions tests/model/common/test_table.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
from nose.tools import assert_dict_equal, assert_list_equal, assert_raises, assert_equal, assert_is_instance
from nose.tools.nontrivial import raises

from coilsnake.exceptions.common.exceptions import TableError, \
TableEntryInvalidYmlRepresentationError, TableEntryMissingDataError, TableSchemaError
from coilsnake.model.common.blocks import Block
Expand All @@ -10,14 +7,18 @@


class GenericTestTable(BaseTestCase):
def setUp(self):
if type(self) is GenericTestTable:
self.skipTest("Base class tests called directly")

def test_from_block(self):
table = Table(num_rows=len(self.TABLE_VALUES),
schema=self.TABLE_SCHEMA)
block = Block()
block.from_list(self.BLOCK_DATA)
table.from_block(block, 0)

assert_list_equal(table.values, self.TABLE_VALUES)
self.assertListEqual(table.values, self.TABLE_VALUES)

def test_to_block(self):
block = Block()
Expand All @@ -27,34 +28,34 @@ def test_to_block(self):
table.values = self.TABLE_VALUES
table.to_block(block, 0)

assert_list_equal(block.to_list(), self.BLOCK_DATA)
self.assertListEqual(block.to_list(), self.BLOCK_DATA)

def test_from_yml_rep(self):
table = Table(num_rows=len(self.TABLE_VALUES),
schema=self.TABLE_SCHEMA)
table.from_yml_rep(self.YML_REP)

assert_list_equal(table.values, self.TABLE_VALUES)
self.assertListEqual(table.values, self.TABLE_VALUES)

def test_to_yml_rep(self):
table = Table(num_rows=len(self.TABLE_VALUES),
schema=self.TABLE_SCHEMA)
table.values = self.TABLE_VALUES
assert_dict_equal(table.to_yml_rep(), self.YML_REP)
self.assertDictEqual(table.to_yml_rep(), self.YML_REP)

def test_from_yml_rep_errors(self):
table = Table(num_rows=1,
schema=self.TABLE_SCHEMA)
for row, column_name, expected_error, expected_error_cause, yml_rep in self.BAD_YML_REPS:
print(row, column_name, expected_error)
with assert_raises(TableError) as cm:
# print(row, column_name, expected_error)
with self.assertRaises(TableError) as cm:
table.from_yml_rep(yml_rep)
e = cm.exception
assert_equal(e.entry, 0)
assert_equal(e.field, column_name)
assert_is_instance(e.cause, expected_error)
self.assertEqual(e.entry, 0)
self.assertEqual(e.field, column_name)
self.assertIsInstance(e.cause, expected_error)
if expected_error_cause:
assert_is_instance(e.cause.cause, expected_error_cause)
self.assertIsInstance(e.cause.cause, expected_error_cause)


class TestGenericLittleEndianTable(GenericTestTable):
Expand Down Expand Up @@ -211,16 +212,16 @@ class TestBitfieldTableEntry(BaseTestCase):
entry_class = BitfieldTableEntry.create(name="test", enumeration_class=enumeration_class, size=1)

def test_from_yml_rep_legacy(self):
assert_equal(self.entry_class.from_yml_rep(0), set())
assert_equal(self.entry_class.from_yml_rep(1), set([0]))
assert_equal(self.entry_class.from_yml_rep(2), set([1]))
assert_equal(self.entry_class.from_yml_rep(3), set([0, 1]))
assert_equal(self.entry_class.from_yml_rep(255), set([0, 1, 2, 3, 4, 5, 6, 7]))
self.assertEqual(self.entry_class.from_yml_rep(0), set())
self.assertEqual(self.entry_class.from_yml_rep(1), set([0]))
self.assertEqual(self.entry_class.from_yml_rep(2), set([1]))
self.assertEqual(self.entry_class.from_yml_rep(3), set([0, 1]))
self.assertEqual(self.entry_class.from_yml_rep(255), set([0, 1, 2, 3, 4, 5, 6, 7]))

@raises(TableEntryInvalidYmlRepresentationError)
def test_from_yml_rep_legacy_too_small(self):
self.entry_class.from_yml_rep(-1)
with self.assertRaises(TableEntryInvalidYmlRepresentationError):
self.entry_class.from_yml_rep(-1)

@raises(TableEntryInvalidYmlRepresentationError)
def test_from_yml_rep_legacy_too_large(self):
self.entry_class.from_yml_rep(256)
with self.assertRaises(TableEntryInvalidYmlRepresentationError):
self.entry_class.from_yml_rep(256)
68 changes: 35 additions & 33 deletions tests/model/eb/test_doors.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from nose.tools import assert_equal, assert_list_equal, assert_dict_equal, assert_not_equal

from coilsnake.model.common.blocks import AllocatableBlock
from coilsnake.model.eb.doors import Door, DoorType, NpcDoor, DestinationDirection, EscalatorOrStairwayDoor, \
StairDirection, RopeOrLadderDoor, ClimbableType, SwitchDoor
Expand All @@ -14,12 +12,14 @@ class GenericTestDoor(BaseTestCase):
DOOR_OFFSET = 0x10
NEW_DOOR_OFFSET = 0x123

def setup(self):
def setUp(self):
if self.DOOR_TYPE is None:
self.skipTest("No door type specified")
self.block = AllocatableBlock()
self.block.from_list([0] * 0x100000)
self.block[self.DOOR_OFFSET:self.DOOR_OFFSET + 5] = self.DOOR_DATA

def teardown(self):
def tearDown(self):
del self.block

def test_baseline(self):
Expand All @@ -28,20 +28,20 @@ def test_baseline(self):
def test_from_block(self):
new_door = self.DOOR_CLASS()
new_door.from_block(self.block, self.DOOR_OFFSET)
assert_equal(new_door, self.door)
self.assertEqual(new_door, self.door)

def test_to_block(self):
self.door.write_to_block(self.block, self.NEW_DOOR_OFFSET, {})
assert_list_equal(self.block[self.DOOR_OFFSET:self.DOOR_OFFSET + 3].to_list(),
self.assertListEqual(self.block[self.DOOR_OFFSET:self.DOOR_OFFSET + 3].to_list(),
[self.door.y, self.door.x, self.DOOR_TYPE])

def test_yml_rep(self):
assert_dict_equal(self.door.yml_rep(), self.YML_REP)
self.assertDictEqual(self.door.yml_rep(), self.YML_REP)

def test_from_yml_rep(self):
new_door = self.DOOR_CLASS()
new_door.from_yml_rep(self.YML_REP)
assert_equal(new_door, self.door)
self.assertEqual(new_door, self.door)


class TestEscalatorDoor(GenericTestDoor):
Expand All @@ -54,8 +54,8 @@ class TestEscalatorDoor(GenericTestDoor):
"X": 251,
"Y": 123}

def setup(self):
super(TestEscalatorDoor, self).setup()
def setUp(self):
super(TestEscalatorDoor, self).setUp()
self.door = EscalatorOrStairwayDoor(x=251, y=123, type=self.DOOR_TYPE, direction=StairDirection.SE)


Expand All @@ -69,8 +69,8 @@ class TestStairwayDoor(GenericTestDoor):
"X": 251,
"Y": 123}

def setup(self):
super(TestStairwayDoor, self).setup()
def setUp(self):
super(TestStairwayDoor, self).setUp()
self.door = EscalatorOrStairwayDoor(x=251, y=123, type=self.DOOR_TYPE, direction=StairDirection.NE)


Expand All @@ -83,8 +83,8 @@ class TestRopeDoor(GenericTestDoor):
"X": 251,
"Y": 123}

def setup(self):
super(TestRopeDoor, self).setup()
def setUp(self):
super(TestRopeDoor, self).setUp()
self.door = RopeOrLadderDoor(x=251, y=123, climbable_type=ClimbableType.ROPE)


Expand All @@ -97,16 +97,18 @@ class TestLadderDoor(GenericTestDoor):
"X": 42,
"Y": 169}

def setup(self):
super(TestLadderDoor, self).setup()
def setUp(self):
super(TestLadderDoor, self).setUp()
self.door = RopeOrLadderDoor(x=42, y=169, climbable_type=ClimbableType.LADDER)


class GenericTestDestinationDoor(GenericTestDoor):
DESTINATION_OFFSET = 0xF0AB0
NEW_DESTINATION_OFFSET = 0x0F1BC0

def setup(self):
def setUp(self):
if self.DOOR_TYPE is None:
self.skipTest("No door type specified")
self.block = AllocatableBlock()
self.block.from_list([0] * 0x100000)
self.block.deallocate((self.NEW_DESTINATION_OFFSET, 0x0F58EE))
Expand All @@ -116,30 +118,30 @@ def setup(self):

def test_to_block(self):
super(GenericTestDestinationDoor, self).test_to_block()
assert_equal(self.block.read_multi(self.NEW_DOOR_OFFSET + 3, 2), self.NEW_DESTINATION_OFFSET & 0xffff)
assert_list_equal(self.block[self.NEW_DESTINATION_OFFSET:(
self.assertEqual(self.block.read_multi(self.NEW_DOOR_OFFSET + 3, 2), self.NEW_DESTINATION_OFFSET & 0xffff)
self.assertListEqual(self.block[self.NEW_DESTINATION_OFFSET:(
self.NEW_DESTINATION_OFFSET + len(self.DESTINATION_DATA))].to_list(),
self.DESTINATION_DATA)

def test_to_block_reuse_destination(self):
tmp_address_labels = dict()
self.door.write_to_block(self.block, self.NEW_DOOR_OFFSET, tmp_address_labels)
self.door.write_to_block(self.block, self.NEW_DOOR_OFFSET + 5, tmp_address_labels)
assert_list_equal(self.block[self.NEW_DOOR_OFFSET:self.NEW_DOOR_OFFSET + 5].to_list(),
self.assertListEqual(self.block[self.NEW_DOOR_OFFSET:self.NEW_DOOR_OFFSET + 5].to_list(),
self.block[self.NEW_DOOR_OFFSET + 5:self.NEW_DOOR_OFFSET + 10].to_list())
assert_equal(len(tmp_address_labels), 1)
self.assertEqual(len(tmp_address_labels), 1)

def test_to_block_do_not_reuse_destination(self):
tmp_address_labels = dict()
self.door.write_to_block(self.block, self.NEW_DOOR_OFFSET, tmp_address_labels)
# This works because every door with a destination has a text_pointer
self.door.text_pointer.address += 1
self.door.write_to_block(self.block, self.NEW_DOOR_OFFSET + 5, tmp_address_labels)
assert_list_equal(self.block[self.NEW_DOOR_OFFSET:self.NEW_DOOR_OFFSET + 3].to_list(),
self.assertListEqual(self.block[self.NEW_DOOR_OFFSET:self.NEW_DOOR_OFFSET + 3].to_list(),
self.block[self.NEW_DOOR_OFFSET + 5:self.NEW_DOOR_OFFSET + 8].to_list())
assert_not_equal(self.block[self.NEW_DOOR_OFFSET + 3:self.NEW_DOOR_OFFSET + 5].to_list(),
self.assertNotEqual(self.block[self.NEW_DOOR_OFFSET + 3:self.NEW_DOOR_OFFSET + 5].to_list(),
self.block[self.NEW_DOOR_OFFSET + 8:self.NEW_DOOR_OFFSET + 10].to_list())
assert_equal(len(tmp_address_labels), 2)
self.assertEqual(len(tmp_address_labels), 2)


class TestSwitchDoor(GenericTestDestinationDoor):
Expand All @@ -156,8 +158,8 @@ class TestSwitchDoor(GenericTestDestinationDoor):
"Event Flag": 0x8098
}

def setup(self):
super(TestSwitchDoor, self).setup()
def setUp(self):
super(TestSwitchDoor, self).setUp()
self.door = SwitchDoor(x=251, y=123, flag=0x8098, text_address=0x00f13245)


Expand All @@ -174,8 +176,8 @@ class TestPersonDoor(GenericTestDestinationDoor):
"Text Pointer": "$ea92a5",
}

def setup(self):
super(TestPersonDoor, self).setup()
def setUp(self):
super(TestPersonDoor, self).setUp()
self.door = NpcDoor(x=251, y=123, type=self.DOOR_TYPE, text_address=0x00ea92a5)


Expand All @@ -192,8 +194,8 @@ class TestObjectDoor(GenericTestDestinationDoor):
"Text Pointer": "$ea82a5",
}

def setup(self):
super(TestObjectDoor, self).setup()
def setUp(self):
super(TestObjectDoor, self).setUp()
self.door = NpcDoor(x=251, y=123, type=self.DOOR_TYPE, text_address=0x00ea82a5)


Expand All @@ -219,8 +221,8 @@ class TestDoor(GenericTestDestinationDoor):
"Text Pointer": "$c531af"
}

def setup(self):
super(TestDoor, self).setup()
def setUp(self):
super(TestDoor, self).setUp()
self.door = Door(x=222, y=111, text_address=0x00c531af, flag=0x231, destination_x=0x711,
destination_y=0x313, destination_direction=DestinationDirection.UP,
destination_style=0x42)
destination_style=0x42)
Loading
Loading