Fast IFS using RPN notation
python
c
x86-64
nasm
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tests_rpn_eval.py 5.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #!/usr/bin/python3
  2. # Copyright 2020 Weber Yann
  3. #
  4. # This file is part of geneifs.
  5. #
  6. # geneifs is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU General Public License as published by
  8. # the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # geneifs is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU General Public License
  17. # along with geneifs. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. import sys
  20. import random
  21. import math
  22. import pickle
  23. import unittest
  24. from unittest import skip
  25. IMAX = (1<<64)-1
  26. try:
  27. import pyrpn
  28. except (ImportError, NameError) as e:
  29. print("Error importing pyrpn. Try to run make.",
  30. file=sys.stderr)
  31. raise e
  32. class TestRpnEval(unittest.TestCase):
  33. def test_arithm(self):
  34. """ Tests arithmetic ops """
  35. ops = [
  36. ('+', '+'),
  37. ('-', '-'),
  38. ('*', '*'),
  39. ('/', '//'),
  40. ('%', '%'),
  41. ('&', '&'),
  42. ('|', '|'),
  43. ('^', '^'),
  44. #('l', '<<'),
  45. #('r', '>>')
  46. ]
  47. for rpn_op, pyop in ops:
  48. with self.subTest('Testing op %s (%s)' % (rpn_op, pyop)):
  49. sys.stderr.write('.')
  50. sys.stderr.flush()
  51. for i in range(0x1000):
  52. op1, op2 = random.randint(0,IMAX), random.randint(1,IMAX)
  53. pyexpr = '%d %s %d' % (op1, pyop, op2)
  54. pyval = eval(pyexpr) % (1<<64)
  55. rpn_expr = "%d %d %s" % (op1, op2, rpn_op)
  56. expr = pyrpn.RPNExpr(rpn_expr, 0)
  57. res = expr.eval()
  58. self.assertEqual(res, pyval,
  59. "TEST#%d %s != %s" % (i, rpn_expr, pyexpr))
  60. def test_not(self):
  61. """ Test unary op """
  62. ops = [('~', '~%d'), ('!', '-%d')]
  63. for rpn_op, pystr in ops:
  64. with self.subTest("Testing op '%sX' (%s)" % (rpn_op, pystr)):
  65. sys.stderr.write('.')
  66. sys.stderr.flush()
  67. for i in range(0x1000):
  68. op1 = random.randint(0, IMAX)
  69. pyexpr = pystr % op1
  70. pyval = eval(pyexpr) % (1<<64)
  71. rpn_expr = '%d %s' % (op1, rpn_op)
  72. expr = pyrpn.RPNExpr(rpn_expr, 0)
  73. res = expr.eval()
  74. self.assertEqual(res, pyval,
  75. "TEST#%d %s != %s" % (i, rpn_expr, pyexpr))
  76. def test_div_zero(self):
  77. """ Test division by zeros """
  78. tests = ['A0 0 /', 'A0 0 %']
  79. for test in tests:
  80. with self.subTest('Testing division by zero using %s' % test):
  81. for i in range(10):
  82. expr = pyrpn.RPNExpr(test, 1)
  83. res = expr.eval(random.randint(0, IMAX))
  84. self.assertEqual(res, 0)
  85. def test_stack_init(self):
  86. """ testing that stack is initialized to 0 """
  87. rpn = ' '.join(['+' for _ in range(15)])
  88. for stack_size in range(4, 128):
  89. with self.subTest('Stack with size %d initialized to 0' % stack_size):
  90. for argc in range(0,256,16):
  91. expr = pyrpn.RPNExpr(rpn, argc, stack_size)
  92. r = expr.eval(*[random.randint(0, IMAX)
  93. for _ in range(argc)])
  94. self.assertEqual(r, 0,
  95. '"+ + + +..." should be 0 but %d returned with %d args' % (r, argc))
  96. def test_lshift_limit(self):
  97. """ 2 << 0x10000 == 0 ? """
  98. expr = pyrpn.RPNExpr("2 %d <<" % 0x100000, 0)
  99. res = expr.eval()
  100. self.assertEqual(res, 0)
  101. def test_rshift_limit(self):
  102. """ (1<<64)-1 >> 0x10000 == 0 ? """
  103. expr = pyrpn.RPNExpr("%d %d >>" % ((1<<64)-1, 0x100000), 0)
  104. res = expr.eval()
  105. self.assertEqual(res, 0)
  106. def test_airthm_extended(self):
  107. """ Extended arithmetic tests """
  108. exprs = (
  109. ('A0 A1 +', '{0} + {1}', 2),
  110. ('A0 A0 A1 + +', '{0} + {1} + {0}', 2),
  111. ('A1 A0 A0 A0 A0 A0 A0 A0 A0 + + + + + + +', '{0} * 8', 2),
  112. ('+', '0', 2),
  113. ('-', '0', 2),
  114. ('A0 A1 -', '{0} - {1}', 2),
  115. ('A0 A0 A1 - -', '{0} - ({0} - {1})', 2),
  116. ('A0 0 A0 - -', '({0} - (0 - {0})) ', 2),
  117. ('*', '0', 2),
  118. ('A0 A1 *', '{0} * {1}', 2),
  119. ('A0 A0 A1 * *', '{0} * {0} * {1}', 2),
  120. ('A0 A0 A0 * *', '{0} * {0} * {0}', 2),
  121. ('A0 A1 x /', '{1} // {0}', 2),
  122. ('A0 A1 A0 pop /', '{0} // {1}', 2),
  123. ('A0 A1 dup +', '{1} + {1}', 2),
  124. )
  125. for rpn, pye, argc in exprs:
  126. expr = pyrpn.RPNExpr(rpn, argc, 8)
  127. for _ in range(0x300):
  128. args = tuple([random.randint(0,255) for _ in range(argc)])
  129. with self.subTest('%s == %s %r' % (rpn, pye, args)):
  130. pyexpr = pye.format(*args)
  131. try:
  132. respy = eval(pyexpr) % (1<<64)
  133. except ZeroDivisionError:
  134. respy = 0
  135. res = expr.eval(*args)
  136. self.assertEqual(res, respy,
  137. '%s%r != %s' % (rpn, args, pyexpr))
  138. if __name__ == '__main__':
  139. unittest.main()