@@ -12,6 +12,16 @@ def simple_err(func, *args):
1212 func .__name__ , args )
1313## pdb.set_trace()
1414
15+ def any_err (func , * args ):
16+ try :
17+ apply (func , args )
18+ except (struct .error , OverflowError , TypeError ):
19+ pass
20+ else :
21+ raise TestFailed , "%s%s did not raise error" % (
22+ func .__name__ , args )
23+ ## pdb.set_trace()
24+
1525simple_err (struct .calcsize , 'Z' )
1626
1727sz = struct .calcsize ('i' )
@@ -113,7 +123,8 @@ def simple_err(func, *args):
113123 raise TestFailed , "unpack(%s, %s) -> (%s,) # expected (%s,)" % (
114124 `fmt` , `res` , `rev` , `arg` )
115125
116- # Some q/Q sanity checks.
126+ ###########################################################################
127+ # q/Q tests.
117128
118129has_native_qQ = 1
119130try :
@@ -124,18 +135,22 @@ def simple_err(func, *args):
124135if verbose :
125136 print "Platform has native q/Q?" , has_native_qQ and "Yes." or "No."
126137
127- simple_err (struct .pack , "Q" , - 1 ) # can't pack -1 as unsigned regardless
138+ any_err (struct .pack , "Q" , - 1 ) # can't pack -1 as unsigned regardless
128139simple_err (struct .pack , "q" , "a" ) # can't pack string as 'q' regardless
129140simple_err (struct .pack , "Q" , "a" ) # ditto, but 'Q'
130141
142+ def string_reverse (s ):
143+ chars = list (s )
144+ chars .reverse ()
145+ return "" .join (chars )
146+
131147def bigendian_to_native (value ):
132148 if isbigendian :
133149 return value
134- chars = list (value )
135- chars .reverse ()
136- return "" .join (chars )
150+ else :
151+ return string_reverse (value )
137152
138- if has_native_qQ :
153+ def test_native_qQ () :
139154 bytes = struct .calcsize ('q' )
140155 # The expected values here are in big-endian format, primarily because
141156 # I'm on a little-endian machine and so this is the clearest way (for
@@ -156,3 +171,147 @@ def bigendian_to_native(value):
156171 verify (retrieved == input ,
157172 "%r-unpack of %r gave %r, not %r" %
158173 (format , got , retrieved , input ))
174+
175+ if has_native_qQ :
176+ test_native_qQ ()
177+
178+ # Standard q/Q (8 bytes; should work on all platforms).
179+
180+ MIN_Q , MAX_Q = 0 , 2L ** 64 - 1
181+ MIN_q , MAX_q = - (2L ** 63 ), 2L ** 63 - 1
182+
183+ import binascii
184+ def test_one_qQ (x , pack = struct .pack ,
185+ unpack = struct .unpack ,
186+ unhexlify = binascii .unhexlify ):
187+ if verbose :
188+ print "trying std q/Q on" , x , "==" , hex (x )
189+
190+ # Try 'q'.
191+ if MIN_q <= x <= MAX_q :
192+ # Try '>q'.
193+ expected = long (x )
194+ if x < 0 :
195+ expected += 1L << 64
196+ assert expected > 0
197+ expected = hex (expected )[2 :- 1 ] # chop "0x" and trailing 'L'
198+ if len (expected ) & 1 :
199+ expected = "0" + expected
200+ expected = unhexlify (expected )
201+ expected = "\x00 " * (8 - len (expected )) + expected
202+
203+ # >q pack work?
204+ got = pack (">q" , x )
205+ verify (got == expected ,
206+ "'>q'-pack of %r gave %r, not %r" %
207+ (x , got , expected ))
208+
209+ # >q unpack work?
210+ retrieved = unpack (">q" , got )[0 ]
211+ verify (x == retrieved ,
212+ "'>q'-unpack of %r gave %r, not %r" %
213+ (got , retrieved , x ))
214+
215+ # Adding any byte should cause a "too big" error.
216+ any_err (unpack , ">q" , '\x01 ' + got )
217+
218+ # Try '<q'.
219+ expected = string_reverse (expected )
220+
221+ # <q pack work?
222+ got = pack ("<q" , x )
223+ verify (got == expected ,
224+ "'<q'-pack of %r gave %r, not %r" %
225+ (x , got , expected ))
226+
227+ # <q unpack work?
228+ retrieved = unpack ("<q" , got )[0 ]
229+ verify (x == retrieved ,
230+ "'<q'-unpack of %r gave %r, not %r" %
231+ (got , retrieved , x ))
232+
233+ # Adding any byte should cause a "too big" error.
234+ any_err (unpack , "<q" , '\x01 ' + got )
235+
236+ else :
237+ # x is out of q's range -- verify pack realizes that.
238+ any_err (pack , '>q' , x )
239+ any_err (pack , '<q' , x )
240+
241+ # Much the same for 'Q'.
242+ if MIN_Q <= x <= MAX_Q :
243+ # Try '>Q'.
244+ expected = long (x )
245+ expected = hex (expected )[2 :- 1 ] # chop "0x" and trailing 'L'
246+ if len (expected ) & 1 :
247+ expected = "0" + expected
248+ expected = unhexlify (expected )
249+ expected = "\x00 " * (8 - len (expected )) + expected
250+
251+ # >Q pack work?
252+ got = pack (">Q" , x )
253+ verify (got == expected ,
254+ "'>Q'-pack of %r gave %r, not %r" %
255+ (x , got , expected ))
256+
257+ # >Q unpack work?
258+ retrieved = unpack (">Q" , got )[0 ]
259+ verify (x == retrieved ,
260+ "'>Q'-unpack of %r gave %r, not %r" %
261+ (got , retrieved , x ))
262+
263+ # Adding any byte should cause a "too big" error.
264+ any_err (unpack , ">Q" , '\x01 ' + got )
265+
266+ # Try '<Q'.
267+ expected = string_reverse (expected )
268+
269+ # <Q pack work?
270+ got = pack ("<Q" , x )
271+ verify (got == expected ,
272+ "'<Q'-pack of %r gave %r, not %r" %
273+ (x , got , expected ))
274+
275+ # <Q unpack work?
276+ retrieved = unpack ("<Q" , got )[0 ]
277+ verify (x == retrieved ,
278+ "'<Q'-unpack of %r gave %r, not %r" %
279+ (got , retrieved , x ))
280+
281+ # Adding any byte should cause a "too big" error.
282+ any_err (unpack , "<Q" , '\x01 ' + got )
283+
284+ else :
285+ # x is out of Q's range -- verify pack realizes that.
286+ any_err (pack , '>Q' , x )
287+ any_err (pack , '<Q' , x )
288+
289+ def test_std_qQ ():
290+ from random import randrange
291+
292+ # Create all interesting powers of 2.
293+ values = []
294+ for exp in range (70 ):
295+ values .append (1L << exp )
296+
297+ # Add some random 64-bit values.
298+ for i in range (50 ):
299+ val = 0L
300+ for j in range (8 ):
301+ val = (val << 8 ) | randrange (256 )
302+ values .append (val )
303+
304+ # Try all those, and their negations, and +-1 from them. Note
305+ # that this tests all power-of-2 boundaries in range, and a few out
306+ # of range, plus +-(2**n +- 1).
307+ for base in values :
308+ for val in - base , base :
309+ for incr in - 1 , 0 , 1 :
310+ x = val + incr
311+ try :
312+ x = int (x )
313+ except OverflowError :
314+ pass
315+ test_one_qQ (x )
316+
317+ test_std_qQ ()
0 commit comments