UHSDR/UHSDR-active-devel/mchf-eclipse/support/Eclipse-Debug-Settings/hex2dfu/intelhex/test.py
2022-08-24 08:41:00 +02:00

1484 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
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, 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 xrange(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 xrange(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 xrange(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 xrange(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 xrange(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()