1# -*- coding: utf-8 -*-
2#
3# timetest.py
4#
5# Copyright (C) 2010 Andrew Resch <andrewresch@gmail.com>
6#
7# rencode is free software.
8#
9# You may redistribute it and/or modify it under the terms of the
10# GNU General Public License, as published by the Free Software
11# Foundation; either version 3 of the License, or (at your option)
12# any later version.
13#
14# rencode is distributed in the hope that it will be useful,
15# but WITHOUT ANY WARRANTY; without even the implied warranty of
16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17# See the GNU General Public License for more details.
18#
19# You should have received a copy of the GNU General Public License
20# along with rencode.    If not, write to:
21#     The Free Software Foundation, Inc.,
22#     51 Franklin Street, Fifth Floor
23#     Boston, MA  02110-1301, USA.
24#
25
26from rencode import _rencode as rencode
27from rencode import rencode_orig
28
29import sys
30# Hack to deal with python 2 and 3 differences with unicode literals.
31if sys.version < '3':
32    import codecs
33    def u(x):
34        return codecs.unicode_escape_decode(x)[0]
35else:
36    unicode = str
37    def u(x):
38        return x
39
40# Encode functions
41
42def test_encode_fixed_pos_int():
43    rencode.dumps(40)
44
45def test_encode_fixed_pos_int_orig():
46    rencode_orig.dumps(40)
47
48def test_encode_fixed_neg_int():
49    rencode.dumps(-29)
50
51def test_encode_fixed_neg_int_orig():
52    rencode_orig.dumps(-29)
53
54def test_encode_int_char_size():
55    rencode.dumps(100)
56    rencode.dumps(-100)
57
58def test_encode_int_char_size_orig():
59    rencode_orig.dumps(100)
60    rencode_orig.dumps(-100)
61
62def test_encode_int_short_size():
63    rencode.dumps(27123)
64    rencode.dumps(-27123)
65
66def test_encode_int_short_size_orig():
67    rencode_orig.dumps(27123)
68    rencode_orig.dumps(-27123)
69
70def test_encode_int_int_size():
71    rencode.dumps(7483648)
72    rencode.dumps(-7483648)
73
74def test_encode_int_int_size_orig():
75    rencode_orig.dumps(7483648)
76    rencode_orig.dumps(-7483648)
77
78def test_encode_int_long_long_size():
79    rencode.dumps(8223372036854775808)
80    rencode.dumps(-8223372036854775808)
81
82def test_encode_int_long_long_size_orig():
83    rencode_orig.dumps(8223372036854775808)
84    rencode_orig.dumps(-8223372036854775808)
85
86bn = int("9"*62)
87def test_encode_int_big_number():
88    rencode.dumps(bn)
89
90def test_encode_int_big_number_orig():
91    rencode_orig.dumps(bn)
92
93def test_encode_float_32bit():
94    rencode.dumps(1234.56)
95
96def test_encode_float_32bit_orig():
97    rencode_orig.dumps(1234.56)
98
99def test_encode_float_64bit():
100    rencode.dumps(1234.56, 64)
101
102def test_encode_float_64bit_orig():
103    rencode_orig.dumps(1234.56, 64)
104
105def test_encode_fixed_str():
106    rencode.dumps(b"foobarbaz")
107
108def test_encode_fixed_str_orig():
109    rencode_orig.dumps(b"foobarbaz")
110
111s = b"f"*255
112def test_encode_str():
113    rencode.dumps(s)
114
115def test_encode_str_orig():
116    rencode_orig.dumps(s)
117
118def test_encode_none():
119    rencode.dumps(None)
120
121def test_encode_none_orig():
122    rencode_orig.dumps(None)
123
124def test_encode_bool():
125    rencode.dumps(True)
126
127def test_encode_bool_orig():
128    rencode_orig.dumps(True)
129
130l = [None, None, None, None]
131def test_encode_fixed_list():
132    rencode.dumps(l)
133
134def test_encode_fixed_list_orig():
135    rencode_orig.dumps(l)
136
137ll = [None]*80
138def test_encode_list():
139    rencode.dumps(ll)
140
141def test_encode_list_orig():
142    rencode_orig.dumps(ll)
143
144keys = b"abcdefghijk"
145d = dict(zip(keys, [None]*len(keys)))
146
147def test_encode_fixed_dict():
148    rencode.dumps(d)
149
150def test_encode_fixed_dict_orig():
151    rencode_orig.dumps(d)
152
153keys2 = b"abcdefghijklmnopqrstuvwxyz1234567890"
154d2 = dict(zip(keys2, [None]*len(keys2)))
155
156def test_encode_dict():
157    rencode.dumps(d2)
158
159def test_encode_dict_orig():
160    rencode_orig.dumps(d2)
161
162
163# Decode functions
164
165def test_decode_fixed_pos_int():
166    rencode.loads(b'(')
167
168def test_decode_fixed_pos_int_orig():
169    rencode_orig.loads(b'(')
170
171def test_decode_fixed_neg_int():
172    rencode.loads(b'b')
173
174def test_decode_fixed_neg_int_orig():
175    rencode_orig.loads(b'b')
176
177def test_decode_int_char_size():
178    rencode.loads(b'>d')
179    rencode.loads(b'>\x9c')
180
181def test_decode_int_char_size_orig():
182    rencode_orig.loads(b'>d')
183    rencode_orig.loads(b'>\x9c')
184
185def test_decode_int_short_size():
186    rencode.loads(b'?i\xf3')
187    rencode.loads(b'?\x96\r')
188
189def test_decode_int_short_size_orig():
190    rencode_orig.loads(b'?i\xf3')
191    rencode_orig.loads(b'?\x96\r')
192
193def test_decode_int_int_size():
194    rencode.loads(b'@\x00r1\x00')
195    rencode.loads(b'@\xff\x8d\xcf\x00')
196
197def test_decode_int_int_size_orig():
198    rencode_orig.loads(b'@\x00r1\x00')
199    rencode_orig.loads(b'@\xff\x8d\xcf\x00')
200
201def test_decode_int_long_long_size():
202    rencode.loads(b'Ar\x1fILX\x9c\x00\x00')
203    rencode.loads(b'A\x8d\xe0\xb6\xb3\xa7d\x00\x00')
204
205def test_decode_int_long_long_size_orig():
206    rencode_orig.loads(b'Ar\x1fILX\x9c\x00\x00')
207    rencode_orig.loads(b'A\x8d\xe0\xb6\xb3\xa7d\x00\x00')
208
209def test_decode_int_big_number():
210    rencode.loads(b'=99999999999999999999999999999999999999999999999999999999999999\x7f')
211
212def test_decode_int_big_number_orig():
213    rencode_orig.loads(b'=99999999999999999999999999999999999999999999999999999999999999\x7f')
214
215def test_decode_float_32bit():
216    rencode.loads(b'BD\x9aQ\xec')
217
218def test_decode_float_32bit_orig():
219    rencode_orig.loads(b'BD\x9aQ\xec')
220
221def test_decode_float_64bit():
222    rencode.loads(b',@\x93J=p\xa3\xd7\n')
223
224def test_decode_float_64bit_orig():
225    rencode_orig.loads(b',@\x93J=p\xa3\xd7\n')
226
227def test_decode_fixed_str():
228    rencode.loads(b'\x89foobarbaz')
229
230def test_decode_fixed_str_orig():
231    rencode_orig.loads(b'\x89foobarbaz')
232
233def test_decode_str():
234    rencode.loads(b'255:fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
235
236def test_decode_str_orig():
237    rencode_orig.loads(b'255:fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff')
238
239def test_decode_none():
240    rencode.loads(b'E')
241
242def test_decode_none_orig():
243    rencode_orig.loads(b'E')
244
245def test_decode_bool():
246    rencode.loads(b'C')
247
248def test_decode_bool_orig():
249    rencode_orig.loads(b'C')
250
251def test_decode_fixed_list():
252    rencode.loads(b'\xc4EEEE')
253
254def test_decode_fixed_list_orig():
255    rencode_orig.loads(b'\xc4EEEE')
256
257def test_decode_list():
258    rencode.loads(b';EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\x7f')
259
260def test_decode_list_orig():
261    rencode_orig.loads(b';EEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEE\x7f')
262
263def test_decode_fixed_dict():
264    rencode.loads(b'q\x81aE\x81cE\x81bE\x81eE\x81dE\x81gE\x81fE\x81iE\x81hE\x81kE\x81jE')
265
266def test_decode_fixed_dict_orig():
267    rencode_orig.loads(b'q\x81aE\x81cE\x81bE\x81eE\x81dE\x81gE\x81fE\x81iE\x81hE\x81kE\x81jE')
268
269def test_decode_dict():
270    rencode.loads(b'<\x811E\x810E\x813E\x812E\x815E\x814E\x817E\x816E\x819E\x818E\x81aE\x81cE\x81bE\x81eE\x81dE\x81gE\x81fE\x81iE\x81hE\x81kE\x81jE\x81mE\x81lE\x81oE\x81nE\x81qE\x81pE\x81sE\x81rE\x81uE\x81tE\x81wE\x81vE\x81yE\x81xE\x81zE\x7f')
271
272def test_decode_dict_orig():
273    rencode_orig.loads(b'<\x811E\x810E\x813E\x812E\x815E\x814E\x817E\x816E\x819E\x818E\x81aE\x81cE\x81bE\x81eE\x81dE\x81gE\x81fE\x81iE\x81hE\x81kE\x81jE\x81mE\x81lE\x81oE\x81nE\x81qE\x81pE\x81sE\x81rE\x81uE\x81tE\x81wE\x81vE\x81yE\x81xE\x81zE\x7f')
274
275
276overall = [
277    b"5ce750f0954ce1537676c7a5fe38b0de30ba7eb65ce750f0954ce1537676c7a5fe38b0de30ba7eb6",
278    b"fixedlength",
279    u("unicodestring"),
280    u("5ce750f0954ce1537676c7a5fe38b0de30ba7eb65ce750f0954ce1537676c7a5fe38b0de30ba7eb6"),
281    -10,
282    10,
283    120,
284    15600,
285    -15600,
286    7483648,
287    -7483648,
288    8223372036854775808,
289    -8223372036854775808,
290    int("9"*62),
291    1227688834.643409,
292    None,
293    True
294]
295
296def test_overall_encode():
297    rencode.dumps(overall)
298
299def test_overall_encode_orig():
300    rencode_orig.dumps(overall)
301
302overall_decode_str = rencode_orig.dumps(overall)
303
304def test_overall_decode():
305    rencode.loads(overall_decode_str)
306
307def test_overall_decode_orig():
308    rencode_orig.loads(overall_decode_str)
309
310
311if __name__ == "__main__":
312    import timeit
313
314    iterations = 10000
315    # ANSI escape codes
316    CSI="\x1B["
317    reset=CSI+"m"
318
319    def do_test(func):
320        print("%s:" % func)
321        new_time = timeit.Timer("%s()" % func, "from __main__ import %s" % func).timeit(iterations)
322        orig_time = timeit.Timer("%s_orig()" % func, "from __main__ import %s_orig" % func).timeit(iterations)
323        if new_time > orig_time:
324            new = CSI + "31m%.3fs%s" % (new_time, reset)
325            orig = CSI + "32m%.3fs%s (%s34m+%.3fs%s) %.2f%%" % (orig_time, reset, CSI, new_time-orig_time, reset, (new_time/orig_time)*100)
326        else:
327            new = CSI + "32m%.3fs%s (%s34m+%.3fs%s) %.2f%%" % (new_time, reset, CSI, orig_time-new_time, reset, (orig_time/new_time)*100)
328            orig = CSI + "31m%.3fs%s" % (orig_time, reset)
329
330        print("\trencode.pyx: %s" % new)
331        print("\trencode.py:  %s" % orig)
332        print("")
333        return (new_time, orig_time)
334
335    if len(sys.argv) == 1:
336        loc = list(locals().keys())
337
338        for t in ("encode", "decode", "overall"):
339            print("*" * 79)
340            print("%s functions:" % (t.title()))
341            print("*" * 79)
342            print("")
343
344            total_new = 0.0
345            total_orig = 0.0
346            for func in loc:
347                if func.startswith("test_%s" % t) and not func.endswith("_orig"):
348                    n, o = do_test(func)
349                    total_new += n
350                    total_orig += o
351
352            print("%s functions totals:" % (t.title()))
353            if total_new > total_orig:
354                new = CSI + "31m%.3fs%s" % (total_new, reset)
355                orig = "%s32m%.3fs%s (%s34m+%.3fs%s) %.2f%%" % (CSI, total_orig, reset, CSI, total_new-total_orig, reset, (total_new/total_orig)*100)
356            else:
357                new = "%s32m%.3fs%s (%s34m+%.3fs%s) %.2f%%" % (CSI, total_new, reset, CSI, total_orig-total_new, reset, (total_orig/total_new)*100)
358                orig = CSI + "31m%.3fs%s" % (total_orig, reset)
359
360            print("\trencode.pyx: %s" % new)
361            print("\trencode.py:  %s" % orig)
362            print("")
363    else:
364        for f in sys.argv[1:]:
365            do_test(f)
366