Skip to content

Commit

Permalink
added unit tests for region collision calculation code
Browse files Browse the repository at this point in the history
  • Loading branch information
cracked-machine committed Feb 4, 2024
1 parent a8d7b1d commit 5d2ee10
Show file tree
Hide file tree
Showing 3 changed files with 234 additions and 17 deletions.
4 changes: 2 additions & 2 deletions mmdiagram/generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,8 @@ def _create_diagram(self, region_list: List[mmdiagram.types.Region]):
def _create_markdown(self, region_list: List[mmdiagram.types.Region]):
with open(self.args.out, "w") as f:
f.write(f"""![memory map diagram]({pathlib.Path(self.args.out).stem}.png)\n""")
f.write("|name|origin|size|remaining|\n")
f.write("|:-|:-|:-|:-|\n")
f.write("|name|origin|size|remaining|collisions\n")
f.write("|:-|:-|:-|:-|:-|\n")
for region in region_list:
f.write(f"{region}\n")

Expand Down
66 changes: 51 additions & 15 deletions mmdiagram/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ def __init__(self, name: str, origin: str, size: str):
"""random colour for region block"""
self.remain: str = None
"""Number of bytes until next region block"""
self.collisons: Dict(str, str) = {}
"""Map of collision regions by name (str) and distance (hex)"""

# both 'lightslategray' and 'lightslategrey' are the same colour
# and we don't want duplicate colours in our diagram
Expand All @@ -44,7 +46,8 @@ def __str__(self):
+ "<span style='color:" + str(self.colour) + "'>" + str(self.name) + "</span>|"\
+ str(self._origin) + "|"\
+ str(self._size) + "|"\
+ str(self.remain) + "|"
+ str(self.remain) + "|"\
+ str(self.collisons) + "|"

def _pick_available_colour(self):
# remove the picked colour from the list so it can't be picked again
Expand Down Expand Up @@ -78,23 +81,56 @@ def calc_nearest_region(self, region_list: List['Region']):
region_distances = {}
print(f"Calculating distances for {self.name}:")
this_region_end = 0
for next_region in region_list:

for probed_region in region_list:
# calc the end address of this and inspected region
this_region_end: int = self.origin + self.size
probed_region_end: int = probed_region.origin + probed_region.size

# skip calculating distance from yourself.
if self.name == next_region.name:
if self.name == probed_region.name:
continue
this_region_end: int = self.origin + self.size
next_region_end: int = next_region.origin + next_region.size
if self.origin > next_region_end:

# skip if 'this' region origin is ahead of the probed region end address
if self.origin > probed_region_end:
continue
next_region_distance: int = next_region.origin - this_region_end
print(f"\t{next_region_distance} to {next_region.name}")
if next_region_distance >= 0:
region_distances[next_region.name] = next_region_distance

probed_region_distance: int = probed_region.origin - this_region_end
print(f"\t{hex(probed_region_distance)} to {probed_region.name}")

# collision detected
if probed_region_distance < 0:
# was the region that collided into us at a lower or higher origin address
if probed_region.origin < self.origin:
# lower so use our origin address as the collion point
self.collisons[probed_region.name] = hex(self.origin)
else:
# higher so use their origin address as the collion point
self.collisons[probed_region.name] = hex(probed_region.origin)

if self.origin < probed_region.origin:
# no distance left
self.remain = hex(probed_region_distance)
pass

else:
# record the distance for later
region_distances[probed_region.name] = probed_region_distance
# set a first value while we have it (in case there are no future collisions)
if not self.remain and not self.collisons:
self.remain = hex(probed_region_distance)
# # if remain not already set to no distance left then set the positive remain distance
elif not self.remain:
self.remain = hex(probed_region_distance)

print(region_distances)
if region_distances:
lowest = min(region_distances, key=region_distances.get)
self.remain = hex(region_distances[lowest])
else:
# after probing each region we must now pick the lowest distance ()
if not self.collisons:
if region_distances:
lowest = min(region_distances, key=region_distances.get)
self.remain = hex(region_distances[lowest])
else:
self.remain = hex(mmdiagram.generator.height - this_region_end)
elif self.collisons and not self.remain:
self.remain = hex(mmdiagram.generator.height - this_region_end)
return "TODO"

181 changes: 181 additions & 0 deletions tests/test_distance.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
import mmdiagram.generator
import unittest
import mmdiagram.types
import mmdiagram.generator

# Check the output report at /tmp/pytest/tests.test_distance.md


def test_distance_three_regions_same_size_no_collisions():
""" """
with unittest.mock.patch('sys.argv',
['mmap_digram.diagram',
'kernel',
'0x10',
'0x30',
'rootfs',
'0x50',
'0x30',
'dtb',
'0x90',
'0x30',
"-o",
f"/tmp/pytest/{__name__}.md"],
mmdiagram.generator.height, 1000):

d = mmdiagram.generator.Diagram()
for region in d._region_list:
if region.name == "kernel":
assert region._origin == "0x10"
assert region._size == "0x30"
assert region.remain == "0x10"
if region.name == "rootfs":
assert region._origin == "0x50"
assert region._size == "0x30"
assert region.remain == "0x10"
if region.name == "dtb":
assert region._origin == "0x90"
assert region._size == "0x30"
assert region.remain == "0x328"


def test_distance_three_regions_diff_size_no_collisions():
""" """
with unittest.mock.patch('sys.argv',
['mmap_digram.diagram',
'kernel',
'0x10',
'0x10',
'rootfs',
'0x50',
'0x20',
'dtb',
'0x90',
'0x30',
"-o",
f"/tmp/pytest/{__name__}.md"],
mmdiagram.generator.height, 1000):
d = mmdiagram.generator.Diagram()
for region in d._region_list:
if region.name == "kernel":
assert region._origin == "0x10"
assert region._size == "0x10"
assert region.remain == "0x30"
if region.name == "rootfs":
assert region._origin == "0x50"
assert region._size == "0x20"
assert region.remain == "0x20"
if region.name == "dtb":
assert region._origin == "0x90"
assert region._size == "0x30"
assert region.remain == "0x328"


def test_distance_three_regions_bottom_collision():
""" """
with unittest.mock.patch('sys.argv',
['mmap_digram.diagram',
'kernel',
'0x10',
'0x60',
'rootfs',
'0x50',
'0x30',
'dtb',
'0x90',
'0x30',
"-o",
f"/tmp/pytest/{__name__}.md"],
mmdiagram.generator.height, 1000):
d = mmdiagram.generator.Diagram()
for region in d._region_list:
if region.name == "kernel":
assert region._origin == "0x10"
assert region._size == "0x60"
assert region.remain == "-0x20"
if region.name == "rootfs":
assert region._origin == "0x50"
assert region._size == "0x30"
assert region.remain == "0x10"
if region.name == "dtb":
assert region._origin == "0x90"
assert region._size == "0x30"
assert region.remain == "0x328"


def test_distance_three_regions_bottom_middle_collision():
""" """
with unittest.mock.patch('sys.argv',
['mmap_digram.diagram',
'kernel',
'0x10',
'0x60',
'rootfs',
'0x50',
'0x50',
'dtb',
'0x90',
'0x30',
"-o",
f"/tmp/pytest/{__name__}.md"],
mmdiagram.generator.height, 1000):
d = mmdiagram.generator.Diagram()
for region in d._region_list:
if region.name == "kernel":
assert region._origin == "0x10"
assert region._size == "0x60"
assert region.remain == "-0x20"
if region.name == "rootfs":
assert region._origin == "0x50"
assert region._size == "0x50"
assert region.remain == "-0x10"
if region.name == "dtb":
assert region._origin == "0x90"
assert region._size == "0x30"
assert region.remain == "0x328"


def test_distance_five_regions_bottom_top_collision():
""" """
with unittest.mock.patch('sys.argv',
['mmap_digram.diagram',
'kernel',
'0x10',
'0x50',
'rootfs',
'0x50',
'0x30',
'dtb',
'0x90',
'0x30',
'uboot',
'0xD0',
'0x50',
'uboot-scr',
'0x110',
'0x30',
"-o",
f"/tmp/pytest/{__name__}.md"],
mmdiagram.generator.height, 1000):
d = mmdiagram.generator.Diagram()
for region in d._region_list:
if region.name == "kernel":
assert region._origin == "0x10"
assert region._size == "0x50"
assert region.remain == "-0x10"
if region.name == "rootfs":
assert region._origin == "0x50"
assert region._size == "0x30"
assert region.remain == "0x10"
if region.name == "dtb":
assert region._origin == "0x90"
assert region._size == "0x30"
assert region.remain == "0x10"
if region.name == "uboot":
assert region._origin == "0xD0"
assert region._size == "0x50"
assert region.remain == "-0x10"
if region.name == "uboot-scr":
assert region._origin == "0x110"
assert region._size == "0x30"
assert region.remain == "0x2a8"

0 comments on commit 5d2ee10

Please sign in to comment.