aboutsummaryrefslogtreecommitdiffstats
path: root/tests/test_project.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/test_project.py')
-rw-r--r--tests/test_project.py75
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