--- /dev/null
+### -*- mode: python, coding: utf-8 -*-
+###
+### Testing implicit conversions
+###
+### (c) 2019 Straylight/Edgeware
+###
+
+###----- Licensing notice ---------------------------------------------------
+###
+### This file is part of the Python interface to Catacomb.
+###
+### Catacomb/Python is free software: you can redistribute it and/or
+### modify it under the terms of the GNU General Public License as
+### published by the Free Software Foundation; either version 2 of the
+### License, or (at your option) any later version.
+###
+### Catacomb/Python is distributed in the hope that it will be useful, but
+### WITHOUT ANY WARRANTY; without even the implied warranty of
+### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+### General Public License for more details.
+###
+### You should have received a copy of the GNU General Public License
+### along with Catacomb/Python. If not, write to the Free Software
+### Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+### USA.
+
+###--------------------------------------------------------------------------
+### Imported modules.
+
+import catacomb as C
+import sys as SYS
+import unittest as U
+import testutils as T
+
+###--------------------------------------------------------------------------
+class TestConvert (U.TestCase):
+ """Test implicit conversions between various mathematical types."""
+
+ def test(me):
+
+ k = C.PrimeField(17)
+ E = k.ec(-3, 4)
+ P = E(1) # order 15
+ kk = C.BinPolyField(0x13)
+ EE = kk.ec(1, 2)
+ PP = E(9) # order 16
+
+ ## `MP' asymmetric operations.
+ me.assertEqual(pow(C.MP(5), 2), 25)
+ me.assertEqual(pow(5, C.MP(2)), 25)
+ me.assertEqual(pow(C.MP(5), 2, 7), 4)
+ me.assertEqual(pow(5, C.MP(2), 7), 4)
+ me.assertEqual(pow(5, 2, C.MP(7)), 4)
+ for bad in [lambda x: [x]]:
+ me.assertRaises(TypeError, pow, C.MP(5), bad(2))
+ me.assertRaises(TypeError, pow, C.MP(5), bad(2), 7)
+ if not T.DEBUGP:
+ ## Debug builds of Python 2 crash here, and it's not our fault. Run
+ ##
+ ## $ python2.7-dbg -c 'pow(long(5), 2, [7])'
+ ##
+ ## to confirm. The `[7]' causes coercion to occur. The first and
+ ## second operands are coerced first, and successfully replaced by
+ ## the results: the first operand (in this case) is unchanged, but
+ ## has its refcount bumped, and the second operand is replaced by the
+ ## result of coercion, which now has a refcount of 1. Then the first
+ ## and third operands are coerced, which fails. Python decrements
+ ## the refcounts of the results of the first coercion, so the second
+ ## operand is now freed and, in debug builds, clobbered. Python then
+ ## tries to format an error message, quoting the types of the
+ ## operands, but one of them has been lost.
+ me.assertRaises(TypeError, pow, C.MP(5), 2, bad(7))
+ me.assertRaises(TypeError, T.lsl, C.MP(5), bad(2))
+
+ ## `GF' asymmetric operations.
+ me.assertEqual(pow(C.GF(0x5), 2), C.GF(0x11))
+ me.assertEqual(pow(C.GF(0x5), C.MP(2)), C.GF(0x11))
+ me.assertEqual(pow(C.GF(5), 2, C.GF(0x13)), C.GF(0x2))
+ for bad in [lambda x: [x]]:
+ me.assertRaises(TypeError, pow, C.GF(5), bad(2))
+ me.assertRaises(TypeError, T.lsl, C.GF(5), bad(2))
+ for bad in [lambda x: [x]]:
+ me.assertRaises(TypeError, pow, bad(5), C.GF(2))
+ me.assertRaises(TypeError, pow, bad(5), C.GF(2), bad(7))
+ me.assertRaises(TypeError, pow, bad(5), bad(2), C.GF(7))
+ me.assertRaises(TypeError, pow, C.GF(5), bad(2), bad(7))
+ if not T.DEBUGP:
+ ## Python bug: see above.
+ me.assertRaises(TypeError, pow, C.GF(5), 2, bad(7))
+
+ ## `MP' and `GF'.
+ me.assertEqual(C.MP(5), 5)
+ me.assertEqual(5, C.MP(5))
+
+ me.assertEqual(C.MP(5) + 3, 8)
+ me.assertEqual(3 + C.MP(5), 8)
+ me.assertRaises(TypeError, T.add, C.MP(5), C.GF(3))
+ me.assertRaises(TypeError, T.add, C.GF(3), C.MP(5))
+
+ ## Field elements.
+ me.assertEqual(k(3) + 4, 7)
+ me.assertEqual(4 + k(3), 7)
+ me.assertEqual(k(3) + C.MP(4), 7)
+ me.assertEqual(C.MP(4) + k(3), 7)
+ me.assertEqual(k(3) + 4, 7)
+ me.assertEqual(C.GF(7) + kk(3), C.GF(4))
+ me.assertEqual(kk(3) + C.GF(7), C.GF(4))
+
+ me.assertRaises(TypeError, T.add, k(3), kk(3))
+ me.assertRaises(TypeError, T.add, kk(3), k(3))
+
+###----- That's all, folks --------------------------------------------------
+
+if __name__ == "__main__": U.main()