Skip to content

Commit

Permalink
- Rename 'add_section' to 'insert_section'
Browse files Browse the repository at this point in the history
- Add some tests
  • Loading branch information
christoph2 committed Oct 23, 2019
1 parent 40deba8 commit 5e64614
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 55 deletions.
45 changes: 36 additions & 9 deletions objutils/image.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ def __init__(self, sections = None, auto_join = True, auto_sort = False, meta =
meta = {}
if not sections:
self.sections = []
elif isinstance(sections, Section):
self.sections = list(sections)
elif hasattr(sections, "__iter__"):
elif isinstance(sections, Section) or hasattr(sections, "__iter__"):
self.sections = list(sections)
else:
raise TypeError("Argument section is of wrong type '{}'".format(sections))
Expand Down Expand Up @@ -120,6 +118,9 @@ def __eq__(self, other):
def __ne__(self, other):
return not (self == other)

def __contains__(self, addr):
return any(addr in sec for sec in self.sections)

def hexdump(self, fp = sys.stdout):
"""
Expand Down Expand Up @@ -211,16 +212,42 @@ def write_string(self, addr, value, encoding = "latin1"):
self._call_address_function("writeString", addr, value, encoding)


def add_section(self, data, address = None, dont_join = False):
address = address if address else self.address # If Address omitted, create continuous address space.
def insert_section(self, data, start_address = None, dont_join = False):
"""
Parameters
----------
data: convertible to bytearray()
Bytes making up the section.
start_address: int
dont_join: bool
Don't join/merge adjacent section.
Notes
-----
Overlapping sections are not supported.
To relace a section use :meth:`replace_section`.
"""
start_address = start_address if start_address else self.address # If Address omitted, create continuous address space.
if start_address in self or (start_address + len(data) - 1) in self:
raise InvalidAddressError("Overlapping adress-space")
if isinstance(data, str):
data = [ord(x) for x in data] # array.array('B',data)
self.sections.append(Section(address, data))
self.sections.append(Section(start_address, data))
if self._need_sorting:
self.sections.sort(key = attrgetter("start_address"))
if self.auto_join:
self.join_sections()
self.address = address + len(data)
self.address = start_address + len(data)

def replace_section(self, data, address = None):
"""
"""

def delete_section(self, address = None):
"""
"""

def join_sections(self, order_segments = False):
self.sections = join_sections(self.sections, order_segments)
Expand Down Expand Up @@ -248,8 +275,8 @@ def __init__(self, sections = None, auto_join = True, auto_sort = False):
self.address = 0
self.auto_join = auto_join

def add_section(self, data, address = None, dont_join = False):
self.image.add_section(data, address, dont_join)
def insert_section(self, data, address = None, dont_join = False):
self.image.insert_section(data, address, dont_join)

def add_metadata(self, meta_data):
pass
Expand Down
23 changes: 12 additions & 11 deletions objutils/section.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,19 @@
"int64": INT64_RANGE,
}


class OutOfBoundsError(Exception):
"""
"""


def filler(ch, n):
"""
:param ch: fill char
:type ch: int between 0 and 255
:param int n: repetition count
:return: bytearray
"""Create an bytearray consisting of `n` `ch`s.
Parameters
----------
ch: int (0 <= ch <= 255)
fill char
n: int
repetition count
Returns
-------
bytearray
"""
if not isinstance(ch, int):
raise TypeError("ch must be of type int")
Expand Down
12 changes: 6 additions & 6 deletions objutils/tests/test_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@

def test_builder_hexdump(capsys):
b0 = Builder()
b0.add_section("hello world!")
b0.insert_section("hello world!")
b0.join_sections()
b0.hexdump(sys.stdout)
captured = capsys.readouterr()
Expand All @@ -55,11 +55,11 @@ class TestBuilderParameters(unittest.TestCase):

def createImage(self, auto_sort = False, auto_join = False):
builder = Builder(auto_sort = auto_sort, auto_join = auto_join)
builder.add_section(range(16), 0x90)
builder.add_section(range(16), 0x80)
builder.add_section(range(16), 0x70)
builder.add_section(range(16), 0x60)
builder.add_section(range(16), 0x50)
builder.insert_section(range(16), 0x90)
builder.insert_section(range(16), 0x80)
builder.insert_section(range(16), 0x70)
builder.insert_section(range(16), 0x60)
builder.insert_section(range(16), 0x50)
return [s.start_address for s in builder.image]

def testBuilderPreservesOrder(self):
Expand Down
24 changes: 12 additions & 12 deletions objutils/tests/test_hexdump.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,10 +85,10 @@
"""

#builder = Builder()
#builder.add_section(range(53), 0x1000)
#builder.add_section(range(0), 0x1000)
#builder.add_section([0] * 512)
#builder.add_section(range(64))
#builder.insert_section(range(53), 0x1000)
#builder.insert_section(range(0), 0x1000)
#builder.insert_section([0] * 512)
#builder.insert_section(range(64))
#builder.join_sections()
#builder.hexdump()

Expand Down Expand Up @@ -117,34 +117,34 @@ def getBuffer(self):
class TestHexdumper(BaseTest):

def testDumpContinuousRange(self):
self.builder.add_section(range(64), 0x1000)
self.builder.insert_section(range(64), 0x1000)
self.builder.join_sections()
self.builder.hexdump(self.buf)
self.assertEqual(self.getBuffer(), TEST1)

def testDumpDiscontinuousRange(self):
self.builder.add_section(range(64), 0x1000)
self.builder.add_section(range(64), 0x2000)
self.builder.insert_section(range(64), 0x1000)
self.builder.insert_section(range(64), 0x2000)
self.builder.join_sections()
self.builder.hexdump(self.buf)
self.assertEqual(self.getBuffer(), TEST2)

def testDumpZeroBytesInBetween(self):
self.builder.add_section(range(64), 0x1000)
self.builder.add_section([0] * 512)
self.builder.add_section(range(64))
self.builder.insert_section(range(64), 0x1000)
self.builder.insert_section([0] * 512)
self.builder.insert_section(range(64))
self.builder.join_sections()
self.builder.hexdump(self.buf)
self.assertEqual(self.getBuffer(), TEST3)

def testDumpOddSizedRow(self):
self.builder.add_section(range(53), 0x1000)
self.builder.insert_section(range(53), 0x1000)
self.builder.join_sections()
self.builder.hexdump(self.buf)
self.assertEqual(self.getBuffer(), TEST4)

def testDumpEmptyRow(self):
self.builder.add_section(range(0), 0x1000)
self.builder.insert_section(range(0), 0x1000)
self.builder.join_sections()
self.builder.hexdump(self.buf)
self.assertEqual(self.getBuffer(), TEST5)
Expand Down
2 changes: 1 addition & 1 deletion objutils/tests/test_hexfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def tearDown(self):


def testAddSectionAliasWorks(self):
self.builder.add_section(range(64), 0x1000)
self.builder.insert_section(range(64), 0x1000)
# Ok, if no exception gets raised.

def testRaisesInvalidChecksumError(self):
Expand Down
76 changes: 63 additions & 13 deletions objutils/tests/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import unittest
import sys

import pytest

from objutils import loads, dumps
from objutils.section import Section
from objutils.image import Image, Builder
from objutils.image import Image, Builder, InvalidAddressError
from objutils.utils import PYTHON_VERSION, create_string_buffer

class BaseTest(unittest.TestCase):
Expand Down Expand Up @@ -46,17 +48,65 @@ def testTwo(self):
def testFailOnUnsupportedType(self):
self.assertRaises(TypeError, Image, 4711)

@pytest.fixture
def images(scope = "module"):
img0 = Image()
img1 = Image()
yield img0, img1
del img0
del img1

def test_insert1(images):
img0, _ = images
img0.insert_section(data = b"0123456789", start_address = 0x100)
assert img0.sections[0].start_address == 0x100
assert img0.sections[0].data == bytearray(b"0123456789")
assert img0.sections[0].length == 10

def test_insert_overlapping1(images):
img0, _ = images
img0.insert_section(data = b"0123456789", start_address = 0x100)
with pytest.raises(InvalidAddressError):
img0.insert_section(data = b"0123456789", start_address = 0x100)

def test_insert_overlapping2(images):
img0, _ = images
img0.insert_section(data = b"0123456789", start_address = 0x100)
with pytest.raises(InvalidAddressError):
img0.insert_section(data = b"0123456789", start_address = 0x109)

def test_insert_overlapping3(images):
img0, _ = images
img0.insert_section(data = b"0123456789", start_address = 0x100)
img0.insert_section(data = b"0123456789", start_address = 0x10a)

def test_insert_overlapping3(images):
img0, _ = images
img0.insert_section(data = b"0123456789", start_address = 0x100)
with pytest.raises(InvalidAddressError):
img0.insert_section(data = b"0123456789", start_address = 0x0f7)

def test_insert_overlapping4(images):
img0, _ = images
img0.insert_section(data = b"0123456789", start_address = 0x100)
img0.insert_section(data = b"0123456789", start_address = 0x0f6)

def test_insert_overlapping5(images):
img0, _ = images
img0.insert_section(data = b"0123456789", start_address = 0x100)
img0.insert_section(data = b"0123456789", start_address = 0x114)
img0.insert_section(data = b"0123456789", start_address = 0x10a)

class Equality(BaseTest):

def testEqualImagesShallCompareEqualCase1(self):
self.b0.add_section("01234567890", 0x1000)
self.b1.add_section("01234567890", 0x1000)
self.b0.insert_section("01234567890", 0x1000)
self.b1.insert_section("01234567890", 0x1000)
self.assertTrue(self.b0.image == self.b1.image)

def testEqualImagesShallCompareEqualCase2(self):
self.b0.add_section("01234567890", 0x1000)
self.b1.add_section("01234567890", 0x1000)
self.b0.insert_section("01234567890", 0x1000)
self.b1.insert_section("01234567890", 0x1000)
self.assertFalse(self.b0.image != self.b1.image)


Expand All @@ -65,12 +115,12 @@ class TestCreateSections(BaseTest):
SREC = b"S1131000000102030405060708090A0B0C0D0E0F64"

def runSectionTestPass(self, data):
self.b0.add_section(data, 0x1000)
self.b0.insert_section(data, 0x1000)
result = dumps('srec', self.b0.image)
self.assertEqual(result, self.SREC)

def runSectionTestFail(self, data):
self.assertRaises(ValueError, self.b0.add_section, data, 0x1000)
self.assertRaises(ValueError, self.b0.insert_section, data, 0x1000)

def testCreateSectionFromStringWorks(self):
self.runSectionTestPass('\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f')
Expand All @@ -86,13 +136,13 @@ def testCreateSectionFromRangeWorks(self):

def testEnsureSectionHasCopySemantics(self):
data = [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]
self.b0.add_section(data, 0x1000)
self.b0.insert_section(data, 0x1000)
data.extend([0x10, 0x20, 0x30, 0x40])
result = dumps('srec', self.b0.image)
self.assertEqual(result, self.SREC)

def testEmptySectionProducesEmptiness(self):
self.b0.add_section([], 0x1000)
self.b0.insert_section([], 0x1000)
result = dumps('srec', self.b0.image)
self.assertEqual(result, b'')

Expand All @@ -109,7 +159,7 @@ def testCreateSectionFromArrayBWorks(self):
self.runSectionTestPass(array('B', [0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f]))

def testOmittedAddressYieldsToZero(self):
self.b0.add_section(range(16))
self.b0.insert_section(range(16))
data = self.b0.image
self.assertEqual(data[0].start_address, 0X00000000)

Expand All @@ -125,9 +175,9 @@ def testOmittedAddressYieldsToZero(self):
class TestImageSlices(BaseTest):

def createImage(self):
self.b0.add_section(range(16), 0x1000)
self.b0.add_section(range(16), 0x2000)
self.b0.add_section(range(16), 0x3000)
self.b0.insert_section(range(16), 0x1000)
self.b0.insert_section(range(16), 0x2000)
self.b0.insert_section(range(16), 0x3000)

def testLenWorks(self):
self.createImage()
Expand Down
2 changes: 1 addition & 1 deletion objutils/tests/test_repr.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class TestRepr(unittest.TestCase):

def testImageRepresentation(self):
builder = Builder()
builder.add_section([x % 256 for x in range(10000)])
builder.insert_section([x % 256 for x in range(10000)])
builder.join_sections()
self.assertEqual(repr(builder.image), RESULT)

Expand Down
4 changes: 2 additions & 2 deletions objutils/tests/test_srec.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class TestRoundtrip(unittest.TestCase):

def testLoadsWorks(self):
builder = Builder()
builder.add_section("Wow! Did you really go through al that trouble to read this?", 0xb000)
builder.insert_section("Wow! Did you really go through al that trouble to read this?", 0xb000)
builder.join_sections()
self.assertEqual(dumps("srec", builder.image, record_type = 1, s5record = False, start_address = 0x0000), SREC1)

Expand All @@ -78,7 +78,7 @@ class TestS19Options(unittest.TestCase):

def createImage(self, record_type, s5record, start_address = None):
builder = Builder()
builder.add_section(range(10), 0x1000)
builder.insert_section(range(10), 0x1000)
builder.join_sections()
return dumps("srec", builder.image, record_type = record_type, s5record = s5record, start_address = start_address)

Expand Down

0 comments on commit 5e64614

Please sign in to comment.