mirror of
https://gitlab.com/xCrystal/pokecrystal-board.git
synced 2024-11-16 11:27:33 -08:00
wonderful world of testing
This commit is contained in:
parent
3bd84c1dac
commit
33d8c7a117
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#utilities to help disassemble pokémon crystal
|
||||
import sys, os, inspect, md5
|
||||
import sys, os, inspect, md5, json
|
||||
from copy import copy
|
||||
|
||||
#for IntervalMap
|
||||
@ -10,6 +10,9 @@ from itertools import izip
|
||||
#for testing all this crap
|
||||
import unittest2 as unittest
|
||||
|
||||
if not hasattr(json, "dumps"):
|
||||
json.dumps = json.write
|
||||
|
||||
#table of pointers to map groups
|
||||
#each map group contains some number of map headers
|
||||
map_group_pointer_table = 0x94000
|
||||
@ -4435,13 +4438,22 @@ def isolate_incbins():
|
||||
|
||||
def process_incbins():
|
||||
"parse incbin lines into memory"
|
||||
global incbins
|
||||
incbins = {} #reset
|
||||
global asm, incbin_lines, processed_incbins
|
||||
#load asm if it isn't ready yet
|
||||
if asm == [] or asm == None:
|
||||
load_asm()
|
||||
#get a list of incbins if that hasn't happened yet
|
||||
if incbin_lines == [] or incbin_lines == None:
|
||||
isolate_incbins()
|
||||
#reset the global that this function creates
|
||||
processed_incbins = {}
|
||||
#for each incbin..
|
||||
for incbin in incbin_lines:
|
||||
#reset this entry
|
||||
processed_incbin = {}
|
||||
|
||||
#get the line number from the global asm line list
|
||||
line_number = asm.index(incbin)
|
||||
|
||||
#forget about all the leading characters
|
||||
partial_start = incbin[21:]
|
||||
start = partial_start.split(",")[0].replace("$", "0x")
|
||||
start = eval(start)
|
||||
@ -4456,20 +4468,19 @@ def process_incbins():
|
||||
end = start + interval
|
||||
end_hex = hex(end).replace("0x", "$")
|
||||
|
||||
processed_incbin = {
|
||||
"line_number": line_number,
|
||||
processed_incbin = {"line_number": line_number,
|
||||
"line": incbin,
|
||||
"start": start,
|
||||
"interval": interval,
|
||||
"end": end,
|
||||
}
|
||||
|
||||
"end": end, }
|
||||
#don't add this incbin if the interval is 0
|
||||
if interval != 0:
|
||||
processed_incbins[line_number] = processed_incbin
|
||||
return processed_incbins
|
||||
|
||||
def reset_incbins():
|
||||
"reset asm before inserting another diff"
|
||||
global asm, incbin_lines, processed_incbins
|
||||
asm = None
|
||||
incbin_lines = []
|
||||
processed_incbins = {}
|
||||
@ -4580,7 +4591,7 @@ def apply_diff(diff, try_fixing=True, do_compile=True):
|
||||
#confirm it's working
|
||||
if do_compile:
|
||||
try:
|
||||
subprocess.check_call("cd ../; make clean; LC_CTYPE=C make", shell=True)
|
||||
subprocess.check_call("cd ../; make clean; make", shell=True)
|
||||
return True
|
||||
except Exception, exc:
|
||||
if try_fixing:
|
||||
@ -4592,13 +4603,6 @@ def index(seq, f):
|
||||
where f(item) == True."""
|
||||
return next((i for i in xrange(len(seq)) if f(seq[i])), None)
|
||||
|
||||
def is_probably_pointer(input):
|
||||
try:
|
||||
blah = int(input, 16)
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
def analyze_intervals():
|
||||
"""find the largest baserom.gbc intervals"""
|
||||
global asm, processed_incbins
|
||||
@ -4614,10 +4618,11 @@ def analyze_intervals():
|
||||
results.append(processed_incbins[key])
|
||||
return results
|
||||
|
||||
def write_all_labels(all_labels):
|
||||
fh = open("labels.json", "w")
|
||||
def write_all_labels(all_labels, filename="labels.json"):
|
||||
fh = open(filename, "w")
|
||||
fh.write(json.dumps(all_labels))
|
||||
fh.close()
|
||||
return True
|
||||
|
||||
def remove_quoted_text(line):
|
||||
"""get rid of content inside quotes
|
||||
@ -4632,9 +4637,12 @@ def remove_quoted_text(line):
|
||||
line = line[0:first] + line[second+1:]
|
||||
return line
|
||||
|
||||
def line_has_comment_address(line, returnable={}):
|
||||
def line_has_comment_address(line, returnable={}, bank=None):
|
||||
"""checks that a given line has a comment
|
||||
with a valid address"""
|
||||
with a valid address, and returns the address in the object.
|
||||
Note: bank is required if you have a 4-letter-or-less address,
|
||||
because otherwise there is no way to figure out which bank
|
||||
is curretly being scanned."""
|
||||
#first set the bank/offset to nada
|
||||
returnable["bank"] = None
|
||||
returnable["offset"] = None
|
||||
@ -4658,7 +4666,7 @@ def line_has_comment_address(line, returnable={}):
|
||||
if line[-2:] == "; ":
|
||||
return False
|
||||
#and multiple whitespace doesn't count either
|
||||
line = line.rstrip(" ")
|
||||
line = line.rstrip(" ").lstrip(" ")
|
||||
if line[-1] == ";":
|
||||
return False
|
||||
#there must be more content after the semicolon
|
||||
@ -4675,7 +4683,7 @@ def line_has_comment_address(line, returnable={}):
|
||||
token = comment.split(" ")[0]
|
||||
if token in ["0x", "$", "x", ":"]:
|
||||
return False
|
||||
bank, offset = None, None
|
||||
offset = None
|
||||
#process a token with a A:B format
|
||||
if ":" in token: #3:3F0A, $3:$3F0A, 0x3:0x3F0A, 3:3F0A
|
||||
#split up the token
|
||||
@ -4717,10 +4725,8 @@ def line_has_comment_address(line, returnable={}):
|
||||
elif "$" in token and not "x" in token:
|
||||
token = token.replace("$", "0x")
|
||||
offset = int(token, 16)
|
||||
bank = calculate_bank(offset)
|
||||
elif "0x" in token and not "$" in token:
|
||||
offset = int(token, 16)
|
||||
bank = calculate_bank(offset)
|
||||
else: #might just be "1" at this point
|
||||
token = token.lower()
|
||||
#check if there are bad characters
|
||||
@ -4728,9 +4734,10 @@ def line_has_comment_address(line, returnable={}):
|
||||
if c not in valid:
|
||||
return False
|
||||
offset = int(token, 16)
|
||||
bank = calculate_bank(offset)
|
||||
if offset == None and bank == None:
|
||||
return False
|
||||
if bank == None:
|
||||
bank = calculate_bank(offset)
|
||||
returnable["bank"] = bank
|
||||
returnable["offset"] = offset
|
||||
returnable["address"] = calculate_pointer(offset, bank=bank)
|
||||
@ -4773,7 +4780,7 @@ def find_labels_without_addresses():
|
||||
return without_addresses
|
||||
|
||||
label_errors = ""
|
||||
def get_labels_between(start_line_id, end_line_id, bank_id):
|
||||
def get_labels_between(start_line_id, end_line_id, bank):
|
||||
labels = []
|
||||
#label = {
|
||||
# "line_number": 15,
|
||||
@ -4782,6 +4789,8 @@ def get_labels_between(start_line_id, end_line_id, bank_id):
|
||||
# "offset": 0x5315,
|
||||
# "address": 0x75315,
|
||||
#}
|
||||
if asm == None:
|
||||
load_asm()
|
||||
sublines = asm[start_line_id : end_line_id + 1]
|
||||
for (current_line_offset, line) in enumerate(sublines):
|
||||
#skip lines without labels
|
||||
@ -4794,7 +4803,7 @@ def get_labels_between(start_line_id, end_line_id, bank_id):
|
||||
#setup a place to store return values from line_has_comment_address
|
||||
returnable = {}
|
||||
#get the address from the comment
|
||||
has_comment = line_has_comment_address(line, returnable=returnable)
|
||||
has_comment = line_has_comment_address(line, returnable=returnable, bank=bank)
|
||||
#skip this line if it has no address in the comment
|
||||
if not has_comment: continue
|
||||
#parse data from line_has_comment_address
|
||||
@ -4813,7 +4822,7 @@ def get_labels_between(start_line_id, end_line_id, bank_id):
|
||||
labels.append(label)
|
||||
return labels
|
||||
|
||||
def scan_for_predefined_labels():
|
||||
def scan_for_predefined_labels(debug=False):
|
||||
"""looks through the asm file for labels at specific addresses,
|
||||
this relies on the label having its address after. ex:
|
||||
|
||||
@ -4825,8 +4834,9 @@ def scan_for_predefined_labels():
|
||||
addresses, but faster to write this script. rgbasm would be able
|
||||
to grab all label addresses better than this script..
|
||||
"""
|
||||
bank_intervals = {}
|
||||
global all_labels
|
||||
all_labels = []
|
||||
bank_intervals = {}
|
||||
|
||||
#figure out line numbers for each bank
|
||||
for bank_id in range(0x7F+1):
|
||||
@ -4836,29 +4846,34 @@ def scan_for_predefined_labels():
|
||||
abbreviation = "0"
|
||||
abbreviation_next = "1"
|
||||
|
||||
#calculate the start/stop line numbers for this bank
|
||||
start_line_id = index(asm, lambda line: "\"bank" + abbreviation + "\"" in line)
|
||||
|
||||
if bank_id != 0x2c:
|
||||
if bank_id != 0x7F:
|
||||
end_line_id = index(asm, lambda line: "\"bank" + abbreviation_next + "\"" in line)
|
||||
end_line_id += 1
|
||||
else:
|
||||
end_line_id = len(asm) - 1
|
||||
|
||||
print "bank" + abbreviation + " starts at " + str(start_line_id) + " to " + str(end_line_id)
|
||||
if debug:
|
||||
output = "bank" + abbreviation + " starts at "
|
||||
output += str(start_line_id)
|
||||
output += " to "
|
||||
output += str(end_line_id)
|
||||
print output
|
||||
|
||||
bank_intervals[bank_id] = {
|
||||
"start": start_line_id,
|
||||
"end": end_line_id,
|
||||
}
|
||||
#store the start/stop line number for this bank
|
||||
bank_intervals[bank_id] = {"start": start_line_id,
|
||||
"end": end_line_id,}
|
||||
#for each bank..
|
||||
for bank_id in bank_intervals.keys():
|
||||
#get the start/stop line number
|
||||
bank_data = bank_intervals[bank_id]
|
||||
|
||||
start_line_id = bank_data["start"]
|
||||
end_line_id = bank_data["end"]
|
||||
|
||||
#get all labels between these two lines
|
||||
labels = get_labels_between(start_line_id, end_line_id, bank_id)
|
||||
#bank_intervals[bank_id]["labels"] = labels
|
||||
all_labels.extend(labels)
|
||||
|
||||
write_all_labels(all_labels)
|
||||
return all_labels
|
||||
|
||||
@ -5112,6 +5127,9 @@ class TestAsmList(unittest.TestCase):
|
||||
self.assertTrue(x(";3:FFAA"))
|
||||
self.assertFalse(x('hello world "how are you today;0x1"'))
|
||||
self.assertTrue(x('hello world "how are you today:0x1";1'))
|
||||
returnable = {}
|
||||
self.assertTrue(x("hello_world: ; 0x4050", returnable=returnable, bank=5))
|
||||
self.assertTrue(returnable["address"] == 0x14050)
|
||||
def test_line_has_label(self):
|
||||
x = line_has_label
|
||||
self.assertTrue(x("hi:"))
|
||||
@ -5135,6 +5153,88 @@ class TestAsmList(unittest.TestCase):
|
||||
labels = find_labels_without_addresses()
|
||||
self.failUnless(len(labels) == 0)
|
||||
asm = None
|
||||
def test_get_labels_between(self):
|
||||
global asm
|
||||
x = get_labels_between#(start_line_id, end_line_id, bank)
|
||||
asm = ["HelloWorld: ;1",
|
||||
"hi:",
|
||||
"no label on this line",
|
||||
]
|
||||
labels = x(0, 2, 0x12)
|
||||
self.assertEqual(len(labels), 1)
|
||||
self.assertEqual(labels[0]["label"], "HelloWorld")
|
||||
del asm
|
||||
def test_scan_for_predefined_labels(self):
|
||||
#label keys: line_number, bank, label, offset, address
|
||||
load_asm()
|
||||
all_labels = scan_for_predefined_labels()
|
||||
label_names = [x["label"] for x in all_labels]
|
||||
self.assertIn("GetFarByte", label_names)
|
||||
self.assertIn("AddNTimes", label_names)
|
||||
self.assertIn("CheckShininess", label_names)
|
||||
def test_write_all_labels(self):
|
||||
"""dumping json into a file"""
|
||||
filename = "test_labels.json"
|
||||
#remove the current file
|
||||
if os.path.exists(filename):
|
||||
os.system("rm " + filename)
|
||||
#make up some labels
|
||||
labels = []
|
||||
#fake label 1
|
||||
label = {"line_number": 5, "bank": 0, "label": "SomeLabel", "address": 0x10}
|
||||
labels.append(label)
|
||||
#fake label 2
|
||||
label = {"line_number": 15, "bank": 2, "label": "SomeOtherLabel", "address": 0x9F0A}
|
||||
labels.append(label)
|
||||
#dump to file
|
||||
write_all_labels(labels, filename=filename)
|
||||
#open the file and read the contents
|
||||
file_handler = open(filename, "r")
|
||||
contents = file_handler.read()
|
||||
file_handler.close()
|
||||
#parse into json
|
||||
obj = json.read(contents)
|
||||
#begin testing
|
||||
self.assertEqual(len(obj), len(labels))
|
||||
self.assertEqual(len(obj), 2)
|
||||
self.assertEqual(obj, labels)
|
||||
def test_isolate_incbins(self):
|
||||
global asm
|
||||
asm = ["123", "456", "789", "abc", "def", "ghi",
|
||||
'INCBIN "baserom.gbc",$12DA,$12F8 - $12DA',
|
||||
"jkl",
|
||||
'INCBIN "baserom.gbc",$137A,$13D0 - $137A']
|
||||
lines = isolate_incbins()
|
||||
self.assertIn(asm[6], lines)
|
||||
self.assertIn(asm[8], lines)
|
||||
for line in lines:
|
||||
self.assertIn("baserom", line)
|
||||
def test_process_incbins(self):
|
||||
global incbin_lines, processed_incbins, asm
|
||||
incbin_lines = ['INCBIN "baserom.gbc",$12DA,$12F8 - $12DA',
|
||||
'INCBIN "baserom.gbc",$137A,$13D0 - $137A']
|
||||
asm = copy(incbin_lines)
|
||||
asm.insert(1, "some other random line")
|
||||
processed_incbins = process_incbins()
|
||||
self.assertEqual(len(processed_incbins), len(incbin_lines))
|
||||
self.assertEqual(processed_incbins[0]["line"], incbin_lines[0])
|
||||
self.assertEqual(processed_incbins[2]["line"], incbin_lines[1])
|
||||
def test_reset_incbins(self):
|
||||
global asm, incbin_lines, processed_incbins
|
||||
#temporarily override the functions
|
||||
global load_asm, isolate_incbins, process_incbins
|
||||
temp1, temp2, temp3 = load_asm, isolate_incbins, process_incbins
|
||||
def load_asm(): pass
|
||||
def isolate_incbins(): pass
|
||||
def process_incbins(): pass
|
||||
#call reset
|
||||
reset_incbins()
|
||||
#check the results
|
||||
self.assertTrue(asm == [] or asm == None)
|
||||
self.assertTrue(incbin_lines == [])
|
||||
self.assertTrue(processed_incbins == {})
|
||||
#reset the original functions
|
||||
load_asm, isolate_incbins, process_incbins = temp1, temp2, temp3
|
||||
class TestMapParsing(unittest.TestCase):
|
||||
#def test_parse_warp_bytes(self):
|
||||
# pass #or raise NotImplementedError, bryan_message
|
||||
|
Loading…
Reference in New Issue
Block a user