pokemon-reverse-engineering.../tests/test_vba.py
2016-08-29 15:13:18 -05:00

288 lines
8.2 KiB
Python

"""
Tests for VBA automation tools
"""
from __future__ import print_function
import unittest
from tests.setup_vba import (
vba,
autoplayer,
keyboard,
)
from tests.bootstrapping import (
bootstrap,
bootstrap_trainer_battle,
)
def setup_wram():
"""
Loads up some default addresses. Should eventually be replaced with the
actual wram parser.
"""
# TODO: this should just be parsed straight out of wram.asm
wram = {}
wram["PlayerDirection"] = 0xd4de
wram["PlayerAction"] = 0xd4e1
wram["MapX"] = 0xd4e6
wram["MapY"] = 0xd4e7
wram["WarpNumber"] = 0xdcb4
wram["MapGroup"] = 0xdcb5
wram["MapNumber"] = 0xdcb6
wram["YCoord"] = 0xdcb7
wram["XCoord"] = 0xdcb8
return wram
class OtherVbaTests(unittest.TestCase):
def test_keyboard_planner(self):
button_sequence = keyboard.plan_typing("an")
expected_result = ["select", "a", "d", "r", "r", "r", "r", "a"]
self.assertEqual(len(expected_result), len(button_sequence))
self.assertEqual(expected_result, button_sequence)
class VbaTests(unittest.TestCase):
cry = None
wram = None
@classmethod
def setUpClass(cls):
cls.bootstrap_state = bootstrap()
cls.wram = setup_wram()
cls.cry = vba.crystal()
cls.vba = cls.cry.vba
cls.vba.state = cls.bootstrap_state
@classmethod
def tearDownClass(cls):
cls.vba.shutdown()
def setUp(self):
# reset to whatever the bootstrapper created
self.vba.state = self.bootstrap_state
def get_wram_value(self, name):
return self.vba.memory[self.wram[name]]
def check_movement(self, direction="d"):
"""
Check if (y, x) before attempting to move and (y, x) after attempting
to move are the same.
"""
start = (self.get_wram_value("MapY"), self.get_wram_value("MapX"))
self.cry.move(direction)
end = (self.get_wram_value("MapY"), self.get_wram_value("MapX"))
return start != end
def bootstrap_name_prompt(self):
runner = autoplayer.SpeedRunner(cry=None)
runner.setup()
runner.skip_intro(stop_at_name_selection=True, skip=False, override=False)
self.cry.vba.press("a", hold=20)
# wait for "Your name?" to show up
while "YOUR NAME?" not in self.cry.get_text():
self.cry.step(count=50)
def test_movement_changes_player_direction(self):
player_direction = self.get_wram_value("PlayerDirection")
self.cry.move("u")
# direction should have changed
self.assertNotEqual(player_direction, self.get_wram_value("PlayerDirection"))
def test_movement_changes_y_coord(self):
first_map_y = self.get_wram_value("MapY")
self.cry.move("u")
# y location should be different
second_map_y = self.get_wram_value("MapY")
self.assertNotEqual(first_map_y, second_map_y)
def test_movement_ends_in_standing(self):
# should start with standing
self.assertEqual(self.get_wram_value("PlayerAction"), 1)
self.cry.move("l")
# should be standing
player_action = self.get_wram_value("PlayerAction")
self.assertEqual(player_action, 1) # 1 = standing
def test_PlaceString(self):
self.cry.call(0, 0x1078)
# where to draw the text
self.cry.registers["hl"] = 0xc4a0
# what text to read from
self.cry.registers["de"] = 0x1276
self.cry.vba.step(count=10)
text = self.cry.get_text()
self.assertTrue("TRAINER" in text)
def test_speedrunner_constructor(self):
runner = autoplayer.SpeedRunner(cry=self.cry)
def test_speedrunner_handle_mom(self):
# TODO: why can't i pass in the current state of the emulator?
runner = autoplayer.SpeedRunner(cry=None)
runner.setup()
runner.skip_intro(skip=True)
runner.handle_mom(skip=False)
# confirm that handle_mom is done by attempting to move on the map
self.assertTrue(self.check_movement("d"))
def test_speedrunner_walk_into_new_bark_town(self):
runner = autoplayer.SpeedRunner(cry=None)
runner.setup()
runner.skip_intro(skip=True)
runner.handle_mom(skip=True)
runner.walk_into_new_bark_town(skip=False)
# test that the game is in a state such that the player can walk
self.assertTrue(self.check_movement("d"))
# check that the map is correct
self.assertEqual(self.get_wram_value("MapGroup"), 24)
self.assertEqual(self.get_wram_value("MapNumber"), 4)
def test_speedrunner_handle_elm(self):
runner = autoplayer.SpeedRunner(cry=None)
runner.setup()
runner.skip_intro(skip=True)
runner.handle_mom(skip=True)
runner.walk_into_new_bark_town(skip=False)
# go through the Elm's Lab sequence
runner.handle_elm("cyndaquil", skip=False)
# test again if the game is in a state where the player can walk
self.assertTrue(self.check_movement("u"))
# check that the map is correct
self.assertEqual(self.get_wram_value("MapGroup"), 24)
self.assertEqual(self.get_wram_value("MapNumber"), 5)
def test_moving_back_and_forth(self):
runner = autoplayer.SpeedRunner(cry=None)
runner.setup()
runner.skip_intro(skip=True)
runner.handle_mom(skip=True)
runner.walk_into_new_bark_town(skip=False)
# must be in New Bark Town
self.assertEqual(self.get_wram_value("MapGroup"), 24)
self.assertEqual(self.get_wram_value("MapNumber"), 4)
runner.cry.move("l")
runner.cry.move("l")
runner.cry.move("l")
runner.cry.move("d")
runner.cry.move("d")
for x in range(0, 10):
runner.cry.move("l")
runner.cry.move("d")
runner.cry.move("r")
runner.cry.move("u")
# must still be in New Bark Town
self.assertEqual(self.get_wram_value("MapGroup"), 24)
self.assertEqual(self.get_wram_value("MapNumber"), 4)
def test_crystal_move_list(self):
runner = autoplayer.SpeedRunner(cry=None)
runner.setup()
runner.skip_intro(skip=True)
runner.handle_mom(skip=True)
runner.walk_into_new_bark_town(skip=False)
# must be in New Bark Town
self.assertEqual(self.get_wram_value("MapGroup"), 24)
self.assertEqual(self.get_wram_value("MapNumber"), 4)
first_map_x = self.get_wram_value("MapX")
runner.cry.move(["l", "l", "l"])
# x location should be different
second_map_x = self.get_wram_value("MapX")
self.assertNotEqual(first_map_x, second_map_x)
# must still be in New Bark Town
self.assertEqual(self.get_wram_value("MapGroup"), 24)
self.assertEqual(self.get_wram_value("MapNumber"), 4)
def test_keyboard_typing_dumb_name(self):
self.bootstrap_name_prompt()
name = "tRaInEr"
self.cry.write(name)
# save this selection
self.cry.vba.press("a", hold=20)
self.assertEqual(name, self.cry.get_player_name())
def test_keyboard_typing_cap_name(self):
names = [
"trainer",
"TRAINER",
"TrAiNeR",
"tRaInEr",
"ExAmPlE",
"Chris",
"Kris",
"beepaaa",
"chris",
"CHRIS",
"Python",
"pYthon",
"pyThon",
"pytHon",
"pythOn",
"pythoN",
"python",
"PyThOn",
"Zot",
"Death",
"Hiro",
"HIRO",
]
self.bootstrap_name_prompt()
start_state = self.cry.vba.state
for name in names:
print("Writing name: " + name)
self.cry.vba.state = start_state
sequence = self.cry.write(name)
print("sequence is: " + str(sequence))
# save this selection
self.cry.vba.press("start", hold=20)
self.cry.vba.press("a", hold=20)
pname = self.cry.get_player_name().replace("@", "")
self.assertEqual(name, pname)
if __name__ == "__main__":
unittest.main()