UHSDR/UHSDR-active-devel/mchf-eclipse/support/hex2dfu/intelhex/test.py
2022-11-08 16:13:55 +01:00

1488 lines
57 KiB
Python

#!/usr/bin/python
# Copyright (c) 2005-2013, Alexander Belchenko
# All rights reserved.
#
# Redistribution and use in source and binary forms,
# with or without modification, are permitted provided
# that the following conditions are met:
#
# * Redistributions of source code must retain
# the above copyright notice, this list of conditions
# and the following disclaimer.
# * Redistributions in binary form must reproduce
# the above copyright notice, this list of conditions
# and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
# * Neither the name of the author nor the names
# of its contributors may be used to endorse
# or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
# OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
# STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""Test suite for IntelHex class."""
import array
from cStringIO import StringIO
import os
import sys
import tempfile
import unittest
# from compat import asbytes, asstr
from . import compat
asbytes = compat.asbytes
asstr = compat.asstr
import intelhex
from intelhex import IntelHex, \
IntelHexError, \
HexReaderError, \
AddressOverlapError, \
HexRecordError, \
RecordLengthError, \
RecordTypeError, \
RecordChecksumError, \
EOFRecordError, \
ExtendedSegmentAddressRecordError, \
ExtendedLinearAddressRecordError, \
StartSegmentAddressRecordError, \
StartLinearAddressRecordError, \
DuplicateStartAddressRecordError, \
InvalidStartAddressValueError, \
_EndOfFile, \
BadAccess16bit, \
hex2bin, \
Record
__docformat__ = 'restructuredtext'
##
# Data for tests
hex8 = '''\
:1004E300CFF0FBE2FDF220FF20F2E120E2FBE6F396
:1004F3000A00FDE0E1E2E3B4E4E5BAE6E7B3BFE80E
:10050300E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8E0
:10051300F9FCFEFF00C0C1C2C3A5C4C5AAC6C7B2C9
:10052300AFC8C9CACBCCCDCECFD0D1D2D3D4D5D6F8
:07053300D7D8D9DCDEDF00A0
:10053A0078227C007D007BFF7A0479F57E007F2398
:10054A0012042F78457C007D007BFF7A0579187E9E
:10055A00007F2212042F759850438920758DDDD2B1
:10056A008ED2996390017BFF7A0479E31200658049
:01057A00FE82
:030000000205A254
:0C05A200787FE4F6D8FD75817A02053AF6
:10035F00E709F608DFFA8046E709F208DFFA803E80
:10036F0088828C83E709F0A3DFFA8032E309F6086D
:10037F00DFFA8078E309F208DFFA807088828C83D5
:10038F00E309F0A3DFFA806489828A83E0A3F60889
:10039F00DFFA805889828A83E0A3F208DFFA804C63
:1003AF0080D280FA80C680D4806980F2803380103A
:1003BF0080A680EA809A80A880DA80E280CA8033A3
:1003CF0089828A83ECFAE493A3C8C582C8CCC5831B
:1003DF00CCF0A3C8C582C8CCC583CCDFE9DEE780EB
:1003EF000D89828A83E493A3F608DFF9ECFAA9F06A
:1003FF00EDFB2289828A83ECFAE0A3C8C582C8CCC0
:10040F00C583CCF0A3C8C582C8CCC583CCDFEADED8
:10041F00E880DB89828A83E493A3F208DFF980CC3A
:10042F0088F0EF60010E4E60C388F0ED2402B40433
:10043F000050B9F582EB2402B4040050AF232345DA
:06044F0082239003AF734D
:10000300E576246AF8E60576227867300702786A8F
:10001300E475F0011204AD0204552000EB7F2ED2EB
:10002300008018EF540F2490D43440D4FF30040BD5
:10003300EF24BFB41A0050032461FFE57760021573
:1000430077057AE57A7002057930070D7867E475EC
:10005300F0011204ADEF02049B02057B7403D20787
:100063008003E4C207F5768B678A688969E4F577CC
:10007300F579F57AE57760077F2012003E80F57504
:1000830078FFC201C200C202C203C205C206C2088F
:1000930012000CFF700D3007057F0012004FAF7A7E
:1000A300AE7922B4255FC2D5C20412000CFF24D05E
:1000B300B40A00501A75F00A787730D50508B6FFF0
:1000C3000106C6A426F620D5047002D20380D924E3
:1000D300CFB41A00EF5004C2E5D20402024FD2019A
:1000E30080C6D20080C0D20280BCD2D580BAD205ED
:1000F30080B47F2012003E2002077401B5770040D0
:10010300F1120003FF12003E020077D208D20680EC
:1001130095120003FB120003FA120003F94A4B7015
:100123000679207A037BFF20022EE577602A7E0082
:100133008E8275830012046E60060EEE657870F091
:10014300C2D5EBC0E0EAC0E0E9C0E0EE120296D00F
:10015300E0F9D0E0FAD0E0FB120455FF60AAEBC04F
:10016300E0EAC0E0E9C0E012003ED0E02401F9D0AB
:10017300E03400FAD0E0FBE5780460DCD578D98080
:10018300877BFF7A027992D202809C791080027970
:1001930008C206C2088008D2D5790A8004790AC247
:1001A300D5E578047002F578E4FAFDFEFF1200034A
:1001B300FC7B08200113120003FD7B1030000A12A0
:1001C3000003FE120003FF7B20EC3382D592D5504F
:1001D30013C3E43000069FFFE49EFEE42001039D69
:1001E300FDE49CFCE4CBF8C201EC700CCFCECDCC8B
:1001F300E824F8F870F38017C3EF33FFEE33FEED16
:1002030033FDEC33FCEB33FB994002FB0FD8E9EBF6
:10021300300105F8D0E0C448B201C0E00AEC4D4E0D
:100223004F78207B0070C2EAB5780040BCC0E01272
:100233000298D0F0D0E0200104C4C0E0C4B201C0F1
:10024300F0120027D0F0D5F0EB0200771204BD01C5
:100253001453018E5800E54C00E14201924F019A7C
:0F02630044019A4900FA4301A0550184460184E1
:100272004501844703405000E92D00ED2E01102B6B
:1002820000F123010E2003292A00A94800000108D9
:100292003F3F3F00790AA2D5200314300509B91067
:1002A200020404B9080104A2D52006025001042068
:1002B20002689202B577005034C0E07F2030031903
:1002C2007F30A20272067205500F1202EFC202C202
:1002D20006C205C2087F30800F300503E9C0E01274
:1002E200003E300503D0E0F9D0E0B577CC300517F9
:1002F2007F30B9100C12003E7F583004077F78809F
:1003020003B9080312003E3002057F2D02003E7F32
:10031200202008F87F2B2006F322920280CF286E3D
:10032200756C6C2900D2011200033001F8C2017809
:100332007730D50108F60200A92D50434958120022
:10034200032403B405004001E490033B9312002F01
:0D035200743A12002FD20375770402018E59
:10045500BB010689828A83E0225002E722BBFE02A5
:09046500E32289828A83E49322D8
:10046E00BB010CE58229F582E5833AF583E0225043
:10047E0006E92582F8E622BBFE06E92582F8E2228D
:0D048E00E58229F582E5833AF583E49322A7
:10049B00BB010689828A83F0225002F722BBFE0140
:0204AB00F3223A
:1004AD00FAE6FB0808E6F925F0F618E6CA3AF62250
:1004BD00D083D082F8E4937012740193700DA3A3CE
:1004CD0093F8740193F5828883E4737402936860E2
:0604DD00EFA3A3A380DFE2
:10057B00EFB40A07740D120586740A309811A89906
:10058B00B8130CC2983098FDA899C298B811F630E0
:07059B0099FDC299F59922B8
:00000001FF
'''
bin8 = array.array('B',[2, 5, 162, 229, 118, 36, 106, 248, 230, 5, 118, 34,
120, 103, 48, 7, 2, 120, 106, 228, 117, 240, 1, 18,
4, 173, 2, 4, 85, 32, 0, 235, 127, 46, 210, 0, 128,
24, 239, 84, 15, 36, 144, 212, 52, 64, 212, 255, 48,
4, 11, 239, 36, 191, 180, 26, 0, 80, 3, 36, 97, 255,
229, 119, 96, 2, 21, 119, 5, 122, 229, 122, 112, 2,
5, 121, 48, 7, 13, 120, 103, 228, 117, 240, 1, 18,
4, 173, 239, 2, 4, 155, 2, 5, 123, 116, 3, 210, 7,
128, 3, 228, 194, 7, 245, 118, 139, 103, 138, 104,
137, 105, 228, 245, 119, 245, 121, 245, 122, 229,
119, 96, 7, 127, 32, 18, 0, 62, 128, 245, 117, 120,
255, 194, 1, 194, 0, 194, 2, 194, 3, 194, 5, 194, 6,
194, 8, 18, 0, 12, 255, 112, 13, 48, 7, 5, 127, 0,
18, 0, 79, 175, 122, 174, 121, 34, 180, 37, 95, 194,
213, 194, 4, 18, 0, 12, 255, 36, 208, 180, 10, 0, 80,
26, 117, 240, 10, 120, 119, 48, 213, 5, 8, 182, 255,
1, 6, 198, 164, 38, 246, 32, 213, 4, 112, 2, 210, 3,
128, 217, 36, 207, 180, 26, 0, 239, 80, 4, 194, 229,
210, 4, 2, 2, 79, 210, 1, 128, 198, 210, 0, 128, 192,
210, 2, 128, 188, 210, 213, 128, 186, 210, 5, 128,
180, 127, 32, 18, 0, 62, 32, 2, 7, 116, 1, 181, 119,
0, 64, 241, 18, 0, 3, 255, 18, 0, 62, 2, 0, 119, 210,
8, 210, 6, 128, 149, 18, 0, 3, 251, 18, 0, 3, 250,
18, 0, 3, 249, 74, 75, 112, 6, 121, 32, 122, 3, 123,
255, 32, 2, 46, 229, 119, 96, 42, 126, 0, 142, 130,
117, 131, 0, 18, 4, 110, 96, 6, 14, 238, 101, 120,
112, 240, 194, 213, 235, 192, 224, 234, 192, 224,
233, 192, 224, 238, 18, 2, 150, 208, 224, 249, 208,
224, 250, 208, 224, 251, 18, 4, 85, 255, 96, 170,
235, 192, 224, 234, 192, 224, 233, 192, 224, 18, 0,
62, 208, 224, 36, 1, 249, 208, 224, 52, 0, 250, 208,
224, 251, 229, 120, 4, 96, 220, 213, 120, 217, 128,
135, 123, 255, 122, 2, 121, 146, 210, 2, 128, 156,
121, 16, 128, 2, 121, 8, 194, 6, 194, 8, 128, 8, 210,
213, 121, 10, 128, 4, 121, 10, 194, 213, 229, 120, 4,
112, 2, 245, 120, 228, 250, 253, 254, 255, 18, 0, 3,
252, 123, 8, 32, 1, 19, 18, 0, 3, 253, 123, 16, 48,
0, 10, 18, 0, 3, 254, 18, 0, 3, 255, 123, 32, 236,
51, 130, 213, 146, 213, 80, 19, 195, 228, 48, 0, 6,
159, 255, 228, 158, 254, 228, 32, 1, 3, 157, 253,
228, 156, 252, 228, 203, 248, 194, 1, 236, 112, 12,
207, 206, 205, 204, 232, 36, 248, 248, 112, 243, 128,
23, 195, 239, 51, 255, 238, 51, 254, 237, 51, 253,
236, 51, 252, 235, 51, 251, 153, 64, 2, 251, 15, 216,
233, 235, 48, 1, 5, 248, 208, 224, 196, 72, 178, 1,
192, 224, 10, 236, 77, 78, 79, 120, 32, 123, 0, 112,
194, 234, 181, 120, 0, 64, 188, 192, 224, 18, 2, 152,
208, 240, 208, 224, 32, 1, 4, 196, 192, 224, 196,
178, 1, 192, 240, 18, 0, 39, 208, 240, 213, 240, 235,
2, 0, 119, 18, 4, 189, 1, 20, 83, 1, 142, 88, 0, 229,
76, 0, 225, 66, 1, 146, 79, 1, 154, 68, 1, 154, 73,
0, 250, 67, 1, 160, 85, 1, 132, 70, 1, 132, 69, 1,
132, 71, 3, 64, 80, 0, 233, 45, 0, 237, 46, 1, 16,
43, 0, 241, 35, 1, 14, 32, 3, 41, 42, 0, 169, 72, 0,
0, 1, 8, 63, 63, 63, 0, 121, 10, 162, 213, 32, 3, 20,
48, 5, 9, 185, 16, 2, 4, 4, 185, 8, 1, 4, 162, 213,
32, 6, 2, 80, 1, 4, 32, 2, 104, 146, 2, 181, 119, 0,
80, 52, 192, 224, 127, 32, 48, 3, 25, 127, 48, 162,
2, 114, 6, 114, 5, 80, 15, 18, 2, 239, 194, 2, 194,
6, 194, 5, 194, 8, 127, 48, 128, 15, 48, 5, 3, 233,
192, 224, 18, 0, 62, 48, 5, 3, 208, 224, 249, 208,
224, 181, 119, 204, 48, 5, 23, 127, 48, 185, 16, 12,
18, 0, 62, 127, 88, 48, 4, 7, 127, 120, 128, 3, 185,
8, 3, 18, 0, 62, 48, 2, 5, 127, 45, 2, 0, 62, 127,
32, 32, 8, 248, 127, 43, 32, 6, 243, 34, 146, 2, 128,
207, 40, 110, 117, 108, 108, 41, 0, 210, 1, 18, 0, 3,
48, 1, 248, 194, 1, 120, 119, 48, 213, 1, 8, 246, 2,
0, 169, 45, 80, 67, 73, 88, 18, 0, 3, 36, 3, 180, 5,
0, 64, 1, 228, 144, 3, 59, 147, 18, 0, 47, 116, 58,
18, 0, 47, 210, 3, 117, 119, 4, 2, 1, 142, 231, 9,
246, 8, 223, 250, 128, 70, 231, 9, 242, 8, 223, 250,
128, 62, 136, 130, 140, 131, 231, 9, 240, 163, 223,
250, 128, 50, 227, 9, 246, 8, 223, 250, 128, 120,
227, 9, 242, 8, 223, 250, 128, 112, 136, 130, 140,
131, 227, 9, 240, 163, 223, 250, 128, 100, 137,
130, 138, 131, 224, 163, 246, 8, 223, 250, 128, 88,
137, 130, 138, 131, 224, 163, 242, 8, 223, 250, 128,
76, 128, 210, 128, 250, 128, 198, 128, 212, 128, 105,
128, 242, 128, 51, 128, 16, 128, 166, 128, 234, 128,
154, 128, 168, 128, 218, 128, 226, 128, 202, 128, 51,
137, 130, 138, 131, 236, 250, 228, 147, 163, 200,
197, 130, 200, 204, 197, 131, 204, 240, 163, 200,
197, 130, 200, 204, 197, 131, 204, 223, 233, 222,
231, 128, 13, 137, 130, 138, 131, 228, 147, 163, 246,
8, 223, 249, 236, 250, 169, 240, 237, 251, 34, 137,
130, 138, 131, 236, 250, 224, 163, 200, 197, 130,
200, 204, 197, 131, 204, 240, 163, 200, 197, 130,
200, 204, 197, 131, 204, 223, 234, 222, 232, 128,
219, 137, 130, 138, 131, 228, 147, 163, 242, 8,
223, 249, 128, 204, 136, 240, 239, 96, 1, 14, 78,
96, 195, 136, 240, 237, 36, 2, 180, 4, 0, 80, 185,
245, 130, 235, 36, 2, 180, 4, 0, 80, 175, 35, 35,
69, 130, 35, 144, 3, 175, 115, 187, 1, 6, 137, 130,
138, 131, 224, 34, 80, 2, 231, 34, 187, 254, 2, 227,
34, 137, 130, 138, 131, 228, 147, 34, 187, 1, 12,
229, 130, 41, 245, 130, 229, 131, 58, 245, 131, 224,
34, 80, 6, 233, 37, 130, 248, 230, 34, 187, 254, 6,
233, 37, 130, 248, 226, 34, 229, 130, 41, 245, 130,
229, 131, 58, 245, 131, 228, 147, 34, 187, 1, 6,
137, 130, 138, 131, 240, 34, 80, 2, 247, 34, 187,
254, 1, 243, 34, 250, 230, 251, 8, 8, 230, 249, 37,
240, 246, 24, 230, 202, 58, 246, 34, 208, 131, 208,
130, 248, 228, 147, 112, 18, 116, 1, 147, 112, 13,
163, 163, 147, 248, 116, 1, 147, 245, 130, 136,
131, 228, 115, 116, 2, 147, 104, 96, 239, 163, 163,
163, 128, 223, 207, 240, 251, 226, 253, 242, 32,
255, 32, 242, 225, 32, 226, 251, 230, 243, 10, 0,
253, 224, 225, 226, 227, 180, 228, 229, 186, 230,
231, 179, 191, 232, 233, 234, 235, 236, 237, 238,
239, 240, 241, 242, 243, 244, 245, 246, 247, 248,
249, 252, 254, 255, 0, 192, 193, 194, 195, 165, 196,
197, 170, 198, 199, 178, 175, 200, 201, 202, 203,
204, 205, 206, 207, 208, 209, 210, 211, 212, 213,
214, 215, 216, 217, 220, 222, 223, 0, 120, 34, 124,
0, 125, 0, 123, 255, 122, 4, 121, 245, 126, 0, 127,
35, 18, 4, 47, 120, 69, 124, 0, 125, 0, 123, 255,
122, 5, 121, 24, 126, 0, 127, 34, 18, 4, 47, 117,
152, 80, 67, 137, 32, 117, 141, 221, 210, 142, 210,
153, 99, 144, 1, 123, 255, 122, 4, 121, 227, 18, 0,
101, 128, 254, 239, 180, 10, 7, 116, 13, 18, 5, 134,
116, 10, 48, 152, 17, 168, 153, 184, 19, 12, 194,
152, 48, 152, 253, 168, 153, 194, 152, 184, 17,
246, 48, 153, 253, 194, 153, 245, 153, 34, 120, 127,
228, 246, 216, 253, 117, 129, 122, 2, 5, 58])
hex16 = """:020000040000FA
:10000000000083120313072055301820042883169C
:10001000031340309900181598168312031318160D
:1000200098170800831203138C1E14281A0808005E
:0C003000831203130C1E1A28990008000C
:00000001FF
"""
bin16 = array.array('H', [0x0000, 0x1283, 0x1303, 0x2007,
0x3055, 0x2018, 0x2804, 0x1683,
0x1303, 0x3040, 0x0099, 0x1518,
0x1698, 0x1283, 0x1303, 0x1618,
0x1798, 0x0008, 0x1283, 0x1303,
0x1E8C, 0x2814, 0x081A, 0x0008,
0x1283, 0x1303, 0x1E0C, 0x281A,
0x0099, 0x0008, 0x3FFF, 0x3FFF])
hex64k = """:020000040000FA
:0100000001FE
:020000040001F9
:0100000002FD
:00000001FF
"""
data64k = {0: 1, 0x10000: 2}
hex_rectype3 = """:0400000312345678E5
:0100000001FE
:00000001FF
"""
data_rectype3 = {0: 1}
start_addr_rectype3 = {'CS': 0x1234, 'IP': 0x5678}
hex_rectype5 = """:0400000512345678E3
:0100000002FD
:00000001FF
"""
data_rectype5 = {0: 2}
start_addr_rectype5 = {'EIP': 0x12345678}
hex_empty_file = ':00000001FF\n'
hex_simple = """\
:10000000000083120313072055301820042883169C
:10001000031340309900181598168312031318160D
:1000200098170800831203138C1E14281A0808005E
:0C003000831203130C1E1A28990008000C
:00000001FF
"""
hex_bug_lp_341051 = """\
:020FEC00E4E738
:040FF00022E122E1F7
:00000001FF
"""
##
# Test cases
class TestIntelHexBase(unittest.TestCase):
"""Base class for all tests.
Provide additional functionality for testing.
"""
def assertRaisesMsg(self, excClass, msg, callableObj, *args, **kwargs):
"""Just like unittest.TestCase.assertRaises,
but checks that the message is right too.
Borrowed from Ned Batchelder Blog.
See: http://www.nedbatchelder.com/blog/200609.html#e20060905T064418
Typical usage::
self.assertRaisesMsg(MyException, "Exception message",
my_function, (arg1, arg2))
"""
try:
callableObj(*args, **kwargs)
except excClass as exc:
excMsg = str(exc)
if not msg:
# No message provided: any message is fine.
return
elif excMsg == msg:
# Message provided, and we got the right message: it passes.
return
else:
# Message provided, and it didn't match: fail!
raise self.failureException(
"Right exception, wrong message: got '%s' expected '%s'" %
(excMsg, msg)
)
else:
if hasattr(excClass, '__name__'):
excName = excClass.__name__
else:
excName = str(excClass)
raise self.failureException(
"Expected to raise %s, didn't get an exception at all" %
excName
)
def assertEqualWrittenData(self, a, b):
return self.assertEquals(a, b, """Written data is incorrect
Should be:
%s
Written:
%s
""" % (a, b))
#/class TestIntelHexBase
class TestIntelHex(TestIntelHexBase):
def setUp(self):
self.f = StringIO(hex8)
def tearDown(self):
self.f.close()
del self.f
def test_init_from_file(self):
ih = IntelHex(self.f)
for addr in range(len(bin8)):
expected = bin8[addr]
actual = ih[addr]
self.assertEqual(expected, actual,
"Data different at address "
"%x (%x != %x)" % (addr, expected, actual))
def test_hex_fromfile(self):
ih = IntelHex()
ih.fromfile(self.f, format='hex')
for addr in range(len(bin8)):
expected = bin8[addr]
actual = ih[addr]
self.assertEqual(expected, actual,
"Data different at address "
"%x (%x != %x)" % (addr, expected, actual))
def test_unicode_filename(self):
handle, fname = tempfile.mkstemp(u'')
os.close(handle)
try:
self.assertTrue(isinstance(fname, unicode))
f = open(fname, 'w')
try:
f.write(hex8)
finally:
f.close()
ih = IntelHex(fname)
self.assertEqual(0, ih.minaddr())
self.assertEqual(len(bin8)-1, ih.maxaddr())
finally:
os.remove(fname)
def test_tobinarray_empty(self):
ih = IntelHex()
ih.padding = 0xFF # set-up explicit padding value and don't use pad parameter
self.assertEqual(array.array('B', []), ih.tobinarray())
self.assertEqual(array.array('B', []), ih.tobinarray(start=0))
self.assertEqual(array.array('B', []), ih.tobinarray(end=2))
self.assertEqual(array.array('B', [255,255,255]), ih.tobinarray(0,2))
def test_tobinarray_with_size(self):
ih = IntelHex(self.f)
self.assertEqual(array.array('B', [2, 5, 162, 229, 118, 36, 106, 248]),
ih.tobinarray(size=8)) # from addr 0
self.assertEqual(array.array('B', [120, 103, 48, 7, 2, 120, 106, 228]),
ih.tobinarray(start=12, size=8))
self.assertEqual(array.array('B', [2, 5, 162, 229, 118, 36, 106, 248]),
ih.tobinarray(end=7, size=8)) # addr: 0..7, 8 bytes
self.assertEqual(array.array('B', [120, 103, 48, 7, 2, 120, 106, 228]),
ih.tobinarray(end=19, size=8)) # addr: 12..19, 8 bytes
self.assertRaises(ValueError, ih.tobinarray, start=0, end=7, size=8)
self.assertRaises(ValueError, ih.tobinarray, end=3, size=8)
self.assertRaises(ValueError, ih.tobinarray, size=0)
self.assertRaises(ValueError, ih.tobinarray, size=-1)
def test_tobinstr(self):
ih = IntelHex(self.f)
s1 = ih.tobinstr()
s2 = asstr(bin8.tostring())
self.assertEqual(s2, s1, "data not equal\n%s\n\n%s" % (s1, s2))
def test_tobinfile(self):
ih = IntelHex(self.f)
sio = StringIO()
ih.tobinfile(sio)
s1 = sio.getvalue()
sio.close()
s2 = asstr(bin8.tostring())
self.assertEqual(s2, s1, "data not equal\n%s\n\n%s" % (s1, s2))
# new API: .tofile universal method
sio = StringIO()
ih.tofile(sio, format='bin')
s1 = sio.getvalue()
sio.close()
s2 = asstr(bin8.tostring())
self.assertEqual(s2, s1, "data not equal\n%s\n\n%s" % (s1, s2))
def test_write_empty_hexfile(self):
ih = intelhex.IntelHex()
sio = StringIO()
ih.write_hex_file(sio)
s = sio.getvalue()
sio.close()
self.assertEqualWrittenData(hex_empty_file, s)
def test_write_hexfile(self):
ih = intelhex.IntelHex(StringIO(hex_simple))
sio = StringIO()
ih.write_hex_file(sio)
s = sio.getvalue()
sio.close()
self.assertEqualWrittenData(hex_simple, s)
# new API: .tofile universal method
sio = StringIO()
ih.tofile(sio, format='hex')
s = sio.getvalue()
sio.close()
self.assertEqualWrittenData(hex_simple, s)
def test_write_hex_bug_341051(self):
ih = intelhex.IntelHex(StringIO(hex_bug_lp_341051))
sio = StringIO()
ih.tofile(sio, format='hex')
s = sio.getvalue()
sio.close()
self.assertEqualWrittenData(hex_bug_lp_341051, s)
def test_write_hex_first_extended_linear_address(self):
ih = IntelHex({0x20000: 0x01})
sio = StringIO()
ih.write_hex_file(sio)
s = sio.getvalue()
sio.close()
# should be
r = [Record.extended_linear_address(2),
Record.data(0x0000, [0x01]),
Record.eof()]
h = '\n'.join(r) + '\n'
# compare
self.assertEqual(h, s)
def test_tofile_wrong_format(self):
ih = IntelHex()
sio = StringIO()
self.assertRaises(ValueError, ih.tofile, sio, {'format': 'bad'})
def test_todict(self):
ih = IntelHex()
self.assertEquals({}, ih.todict())
ih = IntelHex(StringIO(hex64k))
self.assertEquals(data64k, ih.todict())
ih = IntelHex()
ih[1] = 2
ih.start_addr = {'EIP': 1234}
self.assertEquals({1: 2, 'start_addr': {'EIP': 1234}}, ih.todict())
def test_fromdict(self):
ih = IntelHex()
ih.fromdict({1:2, 3:4})
self.assertEquals({1:2, 3:4}, ih.todict())
ih.fromdict({1:5, 6:7})
self.assertEquals({1:5, 3:4, 6:7}, ih.todict())
ih = IntelHex()
ih.fromdict({1: 2, 'start_addr': {'EIP': 1234}})
self.assertEquals({1: 2, 'start_addr': {'EIP': 1234}}, ih.todict())
# bad dict
self.assertRaises(ValueError, ih.fromdict, {'EIP': 1234})
self.assertRaises(ValueError, ih.fromdict, {-1: 1234})
def test_init_from_obj(self):
ih = IntelHex({1:2, 3:4})
self.assertEquals({1:2, 3:4}, ih.todict())
ih.start_addr = {'EIP': 1234}
ih2 = IntelHex(ih)
ih[1] = 5
ih.start_addr = {'EIP': 5678}
self.assertEquals({1:2, 3:4, 'start_addr': {'EIP': 1234}}, ih2.todict())
self.assertNotEqual(id(ih), id(ih2))
def test_dict_interface(self):
ih = IntelHex()
self.assertEquals(0xFF, ih[0]) # padding byte substitution
ih[0] = 1
self.assertEquals(1, ih[0])
del ih[0]
self.assertEquals({}, ih.todict()) # padding byte substitution
def test_len(self):
ih = IntelHex()
self.assertEquals(0, len(ih))
ih[2] = 1
self.assertEquals(1, len(ih))
ih[1000] = 2
self.assertEquals(2, len(ih))
def test__getitem__(self):
ih = IntelHex()
# simple cases
self.assertEquals(0xFF, ih[0])
ih[0] = 1
self.assertEquals(1, ih[0])
# big address
self.assertEquals(0xFF, ih[2**32-1])
# wrong addr type/value for indexing operations
def getitem(index):
return ih[index]
self.assertRaisesMsg(TypeError,
'Address should be >= 0.',
getitem, -1)
self.assertRaisesMsg(TypeError,
"Address has unsupported type: %s" % type('foo'),
getitem, 'foo')
# new object with some data
ih = IntelHex()
ih[0] = 1
ih[1] = 2
ih[2] = 3
ih[10] = 4
# full copy via slicing
ih2 = ih[:]
self.assertTrue(isinstance(ih2, IntelHex))
self.assertEquals({0:1, 1:2, 2:3, 10:4}, ih2.todict())
# other slice operations
self.assertEquals({}, ih[3:8].todict())
self.assertEquals({0:1, 1:2}, ih[0:2].todict())
self.assertEquals({0:1, 1:2}, ih[:2].todict())
self.assertEquals({2:3, 10:4}, ih[2:].todict())
self.assertEquals({0:1, 2:3, 10:4}, ih[::2].todict())
self.assertEquals({10:4}, ih[3:11].todict())
def test__setitem__(self):
ih = IntelHex()
# simple indexing operation
ih[0] = 1
self.assertEquals({0:1}, ih.todict())
# errors
def setitem(a,b):
ih[a] = b
self.assertRaisesMsg(TypeError,
'Address should be >= 0.',
setitem, -1, 0)
self.assertRaisesMsg(TypeError,
"Address has unsupported type: %s" % type('foo'),
setitem, 'foo', 0)
# slice operations
ih[0:4] = range(4)
self.assertEquals({0:0, 1:1, 2:2, 3:3}, ih.todict())
ih[0:] = range(5,9)
self.assertEquals({0:5, 1:6, 2:7, 3:8}, ih.todict())
ih[:4] = range(9,13)
self.assertEquals({0:9, 1:10, 2:11, 3:12}, ih.todict())
# with step
ih = IntelHex()
ih[0:8:2] = range(4)
self.assertEquals({0:0, 2:1, 4:2, 6:3}, ih.todict())
# errors in slice operations
# ih[1:2] = 'a'
self.assertRaisesMsg(ValueError,
'Slice operation expects sequence of bytes',
setitem, slice(1,2,None), 'a')
# ih[0:1] = [1,2,3]
self.assertRaisesMsg(ValueError,
'Length of bytes sequence does not match address range',
setitem, slice(0,1,None), [1,2,3])
# ih[:] = [1,2,3]
self.assertRaisesMsg(TypeError,
'Unsupported address range',
setitem, slice(None,None,None), [1,2,3])
# ih[:2] = [1,2,3]
self.assertRaisesMsg(TypeError,
'start address cannot be negative',
setitem, slice(None,2,None), [1,2,3])
# ih[0:-3:-1] = [1,2,3]
self.assertRaisesMsg(TypeError,
'stop address cannot be negative',
setitem, slice(0,-3,-1), [1,2,3])
def test__delitem__(self):
ih = IntelHex()
ih[0] = 1
del ih[0]
self.assertEquals({}, ih.todict())
# errors
def delitem(addr):
del ih[addr]
self.assertRaises(KeyError, delitem, 1)
self.assertRaisesMsg(TypeError,
'Address should be >= 0.',
delitem, -1)
self.assertRaisesMsg(TypeError,
"Address has unsupported type: %s" % type('foo'),
delitem, 'foo')
# deleting slice
del ih[0:1] # no error here because of slicing
#
def ihex(size=8):
ih = IntelHex()
for i in range(size):
ih[i] = i
return ih
ih = ihex(8)
del ih[:] # delete all data
self.assertEquals({}, ih.todict())
ih = ihex(8)
del ih[2:6]
self.assertEquals({0:0, 1:1, 6:6, 7:7}, ih.todict())
ih = ihex(8)
del ih[::2]
self.assertEquals({1:1, 3:3, 5:5, 7:7}, ih.todict())
def test_addresses(self):
# empty object
ih = IntelHex()
self.assertEquals([], ih.addresses())
self.assertEquals(None, ih.minaddr())
self.assertEquals(None, ih.maxaddr())
# normal object
ih = IntelHex({1:2, 7:8, 10:0})
self.assertEquals([1,7,10], ih.addresses())
self.assertEquals(1, ih.minaddr())
self.assertEquals(10, ih.maxaddr())
def test__get_start_end(self):
# test for private method _get_start_end
# for empty object
ih = IntelHex()
self.assertRaises(intelhex.EmptyIntelHexError, ih._get_start_end)
self.assertRaises(intelhex.EmptyIntelHexError, ih._get_start_end, size=10)
self.assertEquals((0,9), ih._get_start_end(start=0, size=10))
self.assertEquals((1,10), ih._get_start_end(end=10, size=10))
# normal object
ih = IntelHex({1:2, 7:8, 10:0})
self.assertEquals((1,10), ih._get_start_end())
self.assertEquals((1,10), ih._get_start_end(size=10))
self.assertEquals((0,9), ih._get_start_end(start=0, size=10))
self.assertEquals((1,10), ih._get_start_end(end=10, size=10))
class TestIntelHexLoadBin(TestIntelHexBase):
def setUp(self):
self.data = '0123456789'
self.f = StringIO(self.data)
def tearDown(self):
self.f.close()
def test_loadbin(self):
ih = IntelHex()
ih.loadbin(self.f)
self.assertEqual(0, ih.minaddr())
self.assertEqual(9, ih.maxaddr())
self.assertEqual(self.data, ih.tobinstr())
def test_bin_fromfile(self):
ih = IntelHex()
ih.fromfile(self.f, format='bin')
self.assertEqual(0, ih.minaddr())
self.assertEqual(9, ih.maxaddr())
self.assertEqual(self.data, ih.tobinstr())
def test_loadbin_w_offset(self):
ih = IntelHex()
ih.loadbin(self.f, offset=100)
self.assertEqual(100, ih.minaddr())
self.assertEqual(109, ih.maxaddr())
self.assertEqual(self.data, ih.tobinstr())
def test_loadfile_format_bin(self):
ih = IntelHex()
ih.loadfile(self.f, format='bin')
self.assertEqual(0, ih.minaddr())
self.assertEqual(9, ih.maxaddr())
self.assertEqual(self.data, ih.tobinstr())
class TestIntelHexStartingAddressRecords(TestIntelHexBase):
def _test_read(self, hexstr, data, start_addr):
sio = StringIO(hexstr)
ih = IntelHex(sio)
sio.close()
# test data
self.assertEqual(data, ih._buf,
"Internal buffer: %r != %r" %
(data, ih._buf))
self.assertEqual(start_addr, ih.start_addr,
"Start address: %r != %r" %
(start_addr, ih.start_addr))
def test_read_rectype3(self):
self._test_read(hex_rectype3, data_rectype3, start_addr_rectype3)
def test_read_rectype5(self):
self._test_read(hex_rectype5, data_rectype5, start_addr_rectype5)
def _test_write(self, hexstr, data, start_addr, write_start_addr=True):
# prepare
ih = IntelHex(None)
ih._buf = data
ih.start_addr = start_addr
# write
sio = StringIO()
ih.write_hex_file(sio, write_start_addr)
s = sio.getvalue()
sio.close()
# check
self.assertEqualWrittenData(hexstr, s)
def _test_dont_write(self, hexstr, data, start_addr):
expected = ''.join(hexstr.splitlines(True)[1:])
self._test_write(expected, data, start_addr, False)
def test_write_rectype3(self):
self._test_write(hex_rectype3, data_rectype3, start_addr_rectype3)
def test_dont_write_rectype3(self):
self._test_dont_write(hex_rectype3, data_rectype3, start_addr_rectype3)
def test_write_rectype5(self):
self._test_write(hex_rectype5, data_rectype5, start_addr_rectype5)
def test_dont_write_rectype5(self):
self._test_dont_write(hex_rectype5, data_rectype5, start_addr_rectype5)
def test_write_invalid_start_addr_value(self):
ih = IntelHex()
ih.start_addr = {'foo': 1}
sio = StringIO()
self.assertRaises(InvalidStartAddressValueError, ih.write_hex_file, sio)
class TestIntelHex_big_files(TestIntelHexBase):
"""Test that data bigger than 64K read/write correctly"""
def setUp(self):
self.f = StringIO(hex64k)
def tearDown(self):
self.f.close()
del self.f
def test_readfile(self):
ih = intelhex.IntelHex(self.f)
for addr, byte in data64k.items():
readed = ih[addr]
self.assertEquals(byte, readed,
"data not equal at addr %X "
"(%X != %X)" % (addr, byte, readed))
def test_write_hex_file(self):
ih = intelhex.IntelHex(self.f)
sio = StringIO()
ih.write_hex_file(sio)
s = sio.getvalue()
sio.close()
self.assertEqualWrittenData(hex64k, s)
class TestIntelHexGetPutString(TestIntelHexBase):
def setUp(self):
self.ih = IntelHex()
for i in range(10):
self.ih[i] = i
def test_gets(self):
self.assertEquals('\x00\x01\x02\x03\x04\x05\x06\x07', self.ih.gets(0, 8))
self.assertEquals('\x07\x08\x09', self.ih.gets(7, 3))
self.assertRaisesMsg(intelhex.NotEnoughDataError,
'Bad access at 0x1: '
'not enough data to read 10 contiguous bytes',
self.ih.gets, 1, 10)
def test_puts(self):
self.ih.puts(0x03, 'hello')
self.assertEquals('\x00\x01\x02hello\x08\x09', self.ih.gets(0, 10))
def test_getsz(self):
self.assertEquals('', self.ih.getsz(0))
self.assertRaisesMsg(intelhex.NotEnoughDataError,
'Bad access at 0x1: '
'not enough data to read zero-terminated string',
self.ih.getsz, 1)
self.ih[4] = 0
self.assertEquals('\x01\x02\x03', self.ih.getsz(1))
def test_putsz(self):
self.ih.putsz(0x03, 'hello')
self.assertEquals('\x00\x01\x02hello\x00\x09', self.ih.gets(0, 10))
class TestIntelHexDump(TestIntelHexBase):
def test_empty(self):
ih = IntelHex()
sio = StringIO()
ih.dump(sio)
self.assertEquals('', sio.getvalue())
def test_simple(self):
ih = IntelHex()
ih[0] = 0x12
ih[1] = 0x34
sio = StringIO()
ih.dump(sio)
self.assertEquals(
'0000 12 34 -- -- -- -- -- -- -- -- -- -- -- -- -- -- |.4 |\n',
sio.getvalue())
ih[16] = 0x56
ih[30] = 0x98
sio = StringIO()
ih.dump(sio)
self.assertEquals(
'0000 12 34 -- -- -- -- -- -- -- -- -- -- -- -- -- -- |.4 |\n'
'0010 56 -- -- -- -- -- -- -- -- -- -- -- -- -- 98 -- |V . |\n',
sio.getvalue())
def test_minaddr_not_zero(self):
ih = IntelHex()
ih[16] = 0x56
ih[30] = 0x98
sio = StringIO()
ih.dump(sio)
self.assertEquals(
'0010 56 -- -- -- -- -- -- -- -- -- -- -- -- -- 98 -- |V . |\n',
sio.getvalue())
def test_start_addr(self):
ih = IntelHex()
ih[0] = 0x12
ih[1] = 0x34
ih.start_addr = {'CS': 0x1234, 'IP': 0x5678}
sio = StringIO()
ih.dump(sio)
self.assertEquals(
'CS = 0x1234, IP = 0x5678\n'
'0000 12 34 -- -- -- -- -- -- -- -- -- -- -- -- -- -- |.4 |\n',
sio.getvalue())
ih.start_addr = {'EIP': 0x12345678}
sio = StringIO()
ih.dump(sio)
self.assertEquals(
'EIP = 0x12345678\n'
'0000 12 34 -- -- -- -- -- -- -- -- -- -- -- -- -- -- |.4 |\n',
sio.getvalue())
class TestIntelHexMerge(TestIntelHexBase):
def test_merge_empty(self):
ih1 = IntelHex()
ih2 = IntelHex()
ih1.merge(ih2)
self.assertEquals({}, ih1.todict())
def test_merge_simple(self):
ih1 = IntelHex({0:1, 1:2, 2:3})
ih2 = IntelHex({3:4, 4:5, 5:6})
ih1.merge(ih2)
self.assertEquals({0:1, 1:2, 2:3, 3:4, 4:5, 5:6}, ih1.todict())
def test_merge_wrong_args(self):
ih1 = IntelHex()
self.assertRaisesMsg(TypeError, 'other should be IntelHex object',
ih1.merge, {0:1})
self.assertRaisesMsg(ValueError, "Can't merge itself",
ih1.merge, ih1)
ih2 = IntelHex()
self.assertRaisesMsg(ValueError, "overlap argument should be either "
"'error', 'ignore' or 'replace'",
ih1.merge, ih2, overlap='spam')
def test_merge_overlap(self):
# error
ih1 = IntelHex({0:1})
ih2 = IntelHex({0:2})
self.assertRaisesMsg(intelhex.AddressOverlapError,
'Data overlapped at address 0x0',
ih1.merge, ih2, overlap='error')
# ignore
ih1 = IntelHex({0:1})
ih2 = IntelHex({0:2})
ih1.merge(ih2, overlap='ignore')
self.assertEquals({0:1}, ih1.todict())
# replace
ih1 = IntelHex({0:1})
ih2 = IntelHex({0:2})
ih1.merge(ih2, overlap='replace')
self.assertEquals({0:2}, ih1.todict())
def test_merge_start_addr(self):
# this, None
ih1 = IntelHex({'start_addr': {'EIP': 0x12345678}})
ih2 = IntelHex()
ih1.merge(ih2)
self.assertEquals({'start_addr': {'EIP': 0x12345678}}, ih1.todict())
# None, other
ih1 = IntelHex()
ih2 = IntelHex({'start_addr': {'EIP': 0x12345678}})
ih1.merge(ih2)
self.assertEquals({'start_addr': {'EIP': 0x12345678}}, ih1.todict())
# this == other: no conflict
ih1 = IntelHex({'start_addr': {'EIP': 0x12345678}})
ih2 = IntelHex({'start_addr': {'EIP': 0x12345678}})
ih1.merge(ih2)
self.assertEquals({'start_addr': {'EIP': 0x12345678}}, ih1.todict())
# this != other: conflict
## overlap=error
ih1 = IntelHex({'start_addr': {'EIP': 0x12345678}})
ih2 = IntelHex({'start_addr': {'EIP': 0x87654321}})
self.assertRaisesMsg(AddressOverlapError,
'Starting addresses are different',
ih1.merge, ih2, overlap='error')
## overlap=ignore
ih1 = IntelHex({'start_addr': {'EIP': 0x12345678}})
ih2 = IntelHex({'start_addr': {'EIP': 0x87654321}})
ih1.merge(ih2, overlap='ignore')
self.assertEquals({'start_addr': {'EIP': 0x12345678}}, ih1.todict())
## overlap=replace
ih1 = IntelHex({'start_addr': {'EIP': 0x12345678}})
ih2 = IntelHex({'start_addr': {'EIP': 0x87654321}})
ih1.merge(ih2, overlap='replace')
self.assertEquals({'start_addr': {'EIP': 0x87654321}}, ih1.todict())
class TestIntelHex16bit(TestIntelHexBase):
def setUp(self):
self.f = StringIO(hex16)
def tearDown(self):
self.f.close()
del self.f
def test_init_from_file(self):
ih = intelhex.IntelHex16bit(self.f)
def test_init_from_ih(self):
ih = intelhex.IntelHex(self.f)
ih16 = intelhex.IntelHex16bit(ih)
def test_default_padding(self):
ih16 = intelhex.IntelHex16bit()
self.assertEqual(0x0FFFF, ih16.padding)
self.assertEqual(0x0FFFF, ih16[0])
def test_minaddr(self):
ih = intelhex.IntelHex16bit(self.f)
addr = ih.minaddr()
self.assertEqual(0, addr,
'Error in detection of minaddr (0 != 0x%x)' % addr)
def test_maxaddr(self):
ih = intelhex.IntelHex16bit(self.f)
addr = ih.maxaddr()
self.assertEqual(0x001D, addr,
'Error in detection of maxaddr '
'(0x001D != 0x%x)' % addr)
def test_getitem(self):
ih = intelhex.IntelHex16bit(self.f)
ih.padding = 0x3FFF
for addr, word in enumerate(bin16):
self.assertEqual(word, ih[addr],
'Data mismatch at address '
'0x%x (0x%x != 0x%x)' % (addr, word, ih[addr]))
def test_not_enough_data(self):
ih = intelhex.IntelHex()
ih[0] = 1
ih16 = intelhex.IntelHex16bit(ih)
self.assertRaisesMsg(BadAccess16bit,
'Bad access at 0x0: '
'not enough data to read 16 bit value',
lambda x: ih16[x],
0)
def test_write_hex_file(self):
ih = intelhex.IntelHex16bit(self.f)
sio = StringIO()
ih.write_hex_file(sio)
s = sio.getvalue()
sio.close()
fin = StringIO(s)
ih2 = intelhex.IntelHex16bit(fin)
self.assertEqual(ih.tobinstr(), ih2.tobinstr(),
"Written hex file does not equal with original")
def test_bug_988148(self):
# see https://bugs.launchpad.net/intelhex/+bug/988148
ih = intelhex.IntelHex16bit(intelhex.IntelHex())
ih[0] = 25
sio = StringIO()
ih.write_hex_file(sio)
def test_setitem(self):
ih = intelhex.IntelHex16bit(self.f)
old = ih[0]
ih[0] = old ^ 0xFFFF
self.assertNotEqual(old, ih[0],
"Setting new value to internal buffer failed")
def test_tobinarray(self):
ih = intelhex.IntelHex16bit()
ih[0] = 0x1234
ih[1] = 0x5678
self.assertEqual(array.array('H', [0x1234,0x5678,0xFFFF]),
ih.tobinarray(start=0, end=2))
# change padding
ih.padding = 0x3FFF
self.assertEqual(array.array('H', [0x1234,0x5678,0x3FFF]),
ih.tobinarray(start=0, end=2))
#/class TestIntelHex16bit
class TestIntelHexErrors(TestIntelHexBase):
"""Tests for custom errors classes"""
def assertEqualExc(self, message, exception):
return self.assertEqual(message, str(exception))
def test_IntelHexError(self):
self.assertEqualExc('IntelHex base error', IntelHexError())
def test_IntelHexError_message(self):
self.assertEqualExc('IntelHex custom error message',
IntelHexError(msg='IntelHex custom error message'))
self.assertEqualExc('IntelHex base error', IntelHexError(msg=''))
def test_HexReaderError(self):
self.assertEqualExc('Hex reader base error', HexReaderError())
def test_HexRecordError(self):
self.assertEqualExc('Hex file contains invalid record at line 1',
HexRecordError(line=1))
def test_RecordLengthError(self):
self.assertEqualExc('Record at line 1 has invalid length',
RecordLengthError(line=1))
def test_RecordTypeError(self):
self.assertEqualExc('Record at line 1 has invalid record type',
RecordTypeError(line=1))
def test_RecordChecksumError(self):
self.assertEqualExc('Record at line 1 has invalid checksum',
RecordChecksumError(line=1))
def test_EOFRecordError(self):
self.assertEqualExc('File has invalid End-of-File record',
EOFRecordError())
def test_ExtendedSegmentAddressRecordError(self):
self.assertEqualExc(
'Invalid Extended Segment Address Record at line 1',
ExtendedSegmentAddressRecordError(line=1))
def test_ExtendedLinearAddressRecordError(self):
self.assertEqualExc('Invalid Extended Linear Address Record at line 1',
ExtendedLinearAddressRecordError(line=1))
def test_StartSegmentAddressRecordError(self):
self.assertEqualExc('Invalid Start Segment Address Record at line 1',
StartSegmentAddressRecordError(line=1))
def test_StartLinearAddressRecordError(self):
self.assertEqualExc('Invalid Start Linear Address Record at line 1',
StartLinearAddressRecordError(line=1))
def test_DuplicateStartAddressRecord(self):
self.assertEqualExc('Start Address Record appears twice at line 1',
DuplicateStartAddressRecordError(line=1))
def test_InvalidStartAddressValue(self):
self.assertEqualExc("Invalid start address value: {'foo': 1}",
InvalidStartAddressValueError(start_addr={'foo': 1}))
def test_AddressOverlapError(self):
self.assertEqualExc('Hex file has data overlap at address 0x1234 '
'on line 1',
AddressOverlapError(address=0x1234, line=1))
def test_NotEnoughDataError(self):
self.assertEqualExc('Bad access at 0x1234: '
'not enough data to read 10 contiguous bytes',
intelhex.NotEnoughDataError(address=0x1234, length=10))
def test_BadAccess16bit(self):
self.assertEqualExc('Bad access at 0x1234: '
'not enough data to read 16 bit value',
BadAccess16bit(address=0x1234))
#/class TestIntelHexErrors
class TestDecodeHexRecords(TestIntelHexBase):
"""Testing that decoding of records is correct
and all errors raised when needed
"""
def setUp(self):
self.ih = IntelHex()
self.decode_record = self.ih._decode_record
def tearDown(self):
del self.ih
def test_empty_line(self):
# do we could to accept empty lines in hex files?
# standard don't say anything about this
self.decode_record('')
def test_non_empty_line(self):
self.assertRaisesMsg(HexRecordError,
'Hex file contains invalid record at line 1',
self.decode_record,
' ',
1)
def test_short_record(self):
# if record too short it's not a hex record
self.assertRaisesMsg(HexRecordError,
'Hex file contains invalid record at line 1',
self.decode_record,
':',
1)
def test_odd_hexascii_digits(self):
self.assertRaisesMsg(HexRecordError,
'Hex file contains invalid record at line 1',
self.decode_record,
':0100000100F',
1)
def test_invalid_length(self):
self.assertRaisesMsg(RecordLengthError,
'Record at line 1 has invalid length',
self.decode_record,
':FF00000100',
1)
def test_invalid_record_type(self):
self.assertRaisesMsg(RecordTypeError,
'Record at line 1 has invalid record type',
self.decode_record,
':000000FF01',
1)
def test_invalid_checksum(self):
self.assertRaisesMsg(RecordChecksumError,
'Record at line 1 has invalid checksum',
self.decode_record,
':0000000100',
1)
def test_invalid_eof(self):
self.assertRaisesMsg(EOFRecordError,
'File has invalid End-of-File record',
self.decode_record,
':0100000100FE',
1)
def test_invalid_extended_segment(self):
# length
self.assertRaisesMsg(ExtendedSegmentAddressRecordError,
'Invalid Extended Segment Address Record at line 1',
self.decode_record,
':00000002FE',
1)
# addr field
self.assertRaisesMsg(ExtendedSegmentAddressRecordError,
'Invalid Extended Segment Address Record at line 1',
self.decode_record,
':020001020000FB',
1)
def test_invalid_linear_address(self):
# length
self.assertRaisesMsg(ExtendedLinearAddressRecordError,
'Invalid Extended Linear Address Record '
'at line 1',
self.decode_record,
':00000004FC',
1)
# addr field
self.assertRaisesMsg(ExtendedLinearAddressRecordError,
'Invalid Extended Linear Address Record '
'at line 1',
self.decode_record,
':020001040000F9',
1)
def test_invalid_start_segment_addr(self):
# length
self.assertRaisesMsg(StartSegmentAddressRecordError,
'Invalid Start Segment Address Record at line 1',
self.decode_record,
':00000003FD',
1)
# addr field
self.assertRaisesMsg(StartSegmentAddressRecordError,
'Invalid Start Segment Address Record at line 1',
self.decode_record,
':0400010300000000F8',
1)
def test_duplicate_start_segment_addr(self):
self.decode_record(':0400000312345678E5')
self.assertRaisesMsg(DuplicateStartAddressRecordError,
'Start Address Record appears twice at line 2',
self.decode_record,
':0400000300000000F9',
2)
def test_invalid_start_linear_addr(self):
# length
self.assertRaisesMsg(StartLinearAddressRecordError,
'Invalid Start Linear Address Record at line 1',
self.decode_record,
':00000005FB',
1)
# addr field
self.assertRaisesMsg(StartLinearAddressRecordError,
'Invalid Start Linear Address Record at line 1',
self.decode_record,
':0400010500000000F6',
1)
def test_duplicate_start_linear_addr(self):
self.decode_record(':0400000512345678E3')
self.assertRaisesMsg(DuplicateStartAddressRecordError,
'Start Address Record appears twice at line 2',
self.decode_record,
':0400000500000000F7',
2)
def test_addr_overlap(self):
self.decode_record(':0100000000FF')
self.assertRaisesMsg(AddressOverlapError,
'Hex file has data overlap at address 0x0 '
'on line 1',
self.decode_record,
':0100000000FF',
1)
def test_data_record(self):
# should be no exceptions
self.decode_record(':0100000000FF\n')
self.decode_record(':03000100000102F9\r\n')
self.decode_record(':1004E300CFF0FBE2FDF220FF20F2E120E2FBE6F396')
def test_eof(self):
# EOF should raise special exception
self.assertRaises(_EndOfFile, self.decode_record, ':00000001FF')
#/class TestDecodeHexRecords
class TestHex2Bin(unittest.TestCase):
def setUp(self):
self.fin = StringIO(hex8)
self.fout = StringIO()
def tearDown(self):
self.fin.close()
self.fout.close()
def test_hex2bin(self):
ih = hex2bin(self.fin, self.fout)
data = array.array('B', asbytes(self.fout.getvalue()))
for addr in range(len(bin8)):
expected = bin8[addr]
actual = data[addr]
self.assertEqual(expected, actual,
"Data different at address "
"%x (%x != %x)" % (addr, expected, actual))
class TestDiffDumps(unittest.TestCase):
def test_simple(self):
ih1 = IntelHex({1:0x30, 20:0x31, 40:0x33})
ih2 = IntelHex({1:0x30, 20:0x32, 40:0x33})
sio = StringIO()
intelhex.diff_dumps(ih1, ih2, sio)
result = sio.getvalue()
extra = ' '
if sys.version_info[0] >= 3 or sys.version >= '2.7':
extra = ''
shouldbe = (
"--- a%(extra)s\n"
"+++ b%(extra)s\n"
"@@ -1,3 +1,3 @@\n"
" 0000 -- 30 -- -- -- -- -- -- -- -- -- -- -- -- -- -- | 0 |\n"
"-0010 -- -- -- -- 31 -- -- -- -- -- -- -- -- -- -- -- | 1 |\n"
"+0010 -- -- -- -- 32 -- -- -- -- -- -- -- -- -- -- -- | 2 |\n"
" 0020 -- -- -- -- -- -- -- -- 33 -- -- -- -- -- -- -- | 3 |\n"
) % dict(extra=extra)
self.assertEquals(shouldbe, result)
class TestBuildRecords(TestIntelHexBase):
def test__from_bytes(self):
self.assertEqual(':00000001FF',
intelhex.Record._from_bytes([0,0,0,1]))
def test_data(self):
self.assertEqual(':011234005663', intelhex.Record.data(0x1234, [0x56]))
self.assertEqual(':0312340056789059',
intelhex.Record.data(0x1234, [0x56, 0x78, 0x90]))
def test_eof(self):
self.assertEqual(':00000001FF', intelhex.Record.eof())
def test_extended_segment_address(self):
self.assertEqual(':020000021234B6',
intelhex.Record.extended_segment_address(0x1234))
def test_start_segment_address(self):
self.assertEqual(':0400000312345678E5',
intelhex.Record.start_segment_address(0x1234, 0x5678))
def test_extended_linear_address(self):
self.assertEqual(':020000041234B4',
intelhex.Record.extended_linear_address(0x1234))
def test_start_linear_address(self):
self.assertEqual(':0400000512345678E3',
intelhex.Record.start_linear_address(0x12345678))
class Test_GetFileAndAddrRange(TestIntelHexBase):
def test_simple(self):
self.assertEqual(('filename.hex', None, None),
intelhex._get_file_and_addr_range('filename.hex'))
self.assertEqual(('f', None, None),
intelhex._get_file_and_addr_range('f'))
self.assertEqual(('filename.hex', 1, None),
intelhex._get_file_and_addr_range('filename.hex:1:'))
self.assertEqual(('filename.hex', None, 10),
intelhex._get_file_and_addr_range('filename.hex::A'))
self.assertEqual(('filename.hex', 1, 10),
intelhex._get_file_and_addr_range('filename.hex:1:A'))
self.assertEqual(('filename.hex', 1, 10),
intelhex._get_file_and_addr_range('filename.hex:0001:000A'))
def test_bad_notation(self):
self.assertRaises(intelhex._BadFileNotation,
intelhex._get_file_and_addr_range, 'filename.hex:')
self.assertRaises(intelhex._BadFileNotation,
intelhex._get_file_and_addr_range, 'filename.hex:::')
self.assertRaises(intelhex._BadFileNotation,
intelhex._get_file_and_addr_range, 'C:\\filename.hex:', True)
def test_drive_letter(self):
self.assertEqual(('C:\\filename.hex', None, None),
intelhex._get_file_and_addr_range('C:\\filename.hex', True))
self.assertEqual(('C:\\filename.hex', 1, None),
intelhex._get_file_and_addr_range('C:\\filename.hex:1:', True))
self.assertEqual(('C:\\filename.hex', None, 10),
intelhex._get_file_and_addr_range('C:\\filename.hex::A', True))
self.assertEqual(('C:\\filename.hex', 1, 10),
intelhex._get_file_and_addr_range('C:\\filename.hex:1:A', True))
self.assertEqual(('C:\\filename.hex', 1, 10),
intelhex._get_file_and_addr_range('C:\\filename.hex:0001:000A', True))
##
# MAIN
if __name__ == '__main__':
unittest.main()