diff options
Diffstat (limited to 'tests/test_project.py')
| -rw-r--r-- | tests/test_project.py | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/tests/test_project.py b/tests/test_project.py index 1f93d4a..91fd250 100644 --- a/tests/test_project.py +++ b/tests/test_project.py @@ -124,6 +124,41 @@ def main() -> int: extra = _bin(os.path.join(src, "extra")) proj2.add(extra, label="extra") check("add() appends a binary", proj2.by_label("extra") is not None) + + # -- re-adding must not duplicate (matched by resolved path) --------- # + n = len(proj2.refs) + proj2.add(extra) + check("re-adding the same path is a no-op", len(proj2.refs) == n, + f"{[r.label for r in proj2.refs]}") + os.chdir(src) + proj2.add("./extra") # same file, relative + proj2.add(os.path.join(src, "..", "src", "extra")) # same file, messy + check("a different spelling of the same path is a no-op", + len(proj2.refs) == n, f"{[r.label for r in proj2.refs]}") + link = os.path.join(src, "extra_link") + os.symlink(extra, link) + proj2.add(link) + check("a symlink to an existing binary is a no-op", + len(proj2.refs) == n, f"{[r.label for r in proj2.refs]}") + + # ...but a DIFFERENT file with the same basename must still be added + other_dir = os.path.join(tmp, "other2") + os.makedirs(other_dir) + twin = _bin(os.path.join(other_dir, "extra"), b"\x7fELF a different extra") + proj2.add(twin) + check("a same-named file from another directory IS added", + len(proj2.refs) == n + 1 + and proj2.by_source(twin) is not None + and proj2.by_source(extra) is not proj2.by_source(twin), + f"{[(r.label, r.source) for r in proj2.refs[-2:]]}") + check("the twins get distinct labels", + len({r.label for r in proj2.refs}) == len(proj2.refs), + f"{[r.label for r in proj2.refs]}") + check("create() also drops repeats on the command line", + len(Project.create(os.path.join(tmp, "dup.json"), + [extra, "./extra", extra]).refs) == 1) + os.chdir(tmp) + proj2.remove(proj2.by_source(twin).label) check("remove() drops one", proj2.remove("extra") and proj2.by_label("extra") is None) @@ -150,6 +185,46 @@ def main() -> int: except ProjectError: check("staging a missing binary raises ProjectError", True) + # -- load options for headerless blobs --------------------------------- # + with tempfile.TemporaryDirectory() as tmp: + src = os.path.join(tmp, "src"); os.makedirs(src) + blob = os.path.join(src, "fw.bin") + with open(blob, "wb") as f: + f.write(b"\x00" * 64) + proj = Project.create(os.path.join(tmp, "p.json"), [blob], name="p", + load={"processor": "arm", "base": 0x8000000}) + r = proj.refs[0] + check("create() records load options per binary", + r.processor == "arm" and r.base == 0x8000000, + f"proc={r.processor!r} base={r.base:#x}") + # -b is PARAGRAPHS: 0x8000000 >> 4 == 0x800000. Getting this wrong loads + # the image 16x too high and every address in the database is wrong. + check("base is converted to IDA's paragraph units", + r.load_args == "-parm -b800000", r.load_args) + + proj2 = Project.load(proj.path) + check("load options survive a round-trip through the file", + proj2.refs[0].load_args == "-parm -b800000", + proj2.refs[0].load_args) + + blob2 = os.path.join(src, "other.bin") + with open(blob2, "wb") as f: + f.write(b"\x00" * 64) + r2 = proj2.add(blob2, load={"processor": "mipsb"}) + check("add() takes load options too", + r2.load_args == "-pmipsb", r2.load_args) + + # a normal ELF needs none of this and must pass nothing + check("a binary with no load options passes no switches", + Project.create(os.path.join(tmp, "q.json"), [blob], + name="q").refs[0].load_args == "") + + # addresses get written by hand, so accept how people write them + proj3 = Project.create(os.path.join(tmp, "r.json"), [blob], name="r", + load={"base": "0x1000"}) + check("a base given as a hex STRING is parsed", + proj3.refs[0].base == 0x1000, f"{proj3.refs[0].base}") + print(f"\n{PASS} passed, {FAIL} failed") return 1 if FAIL else 0 |
