#!/usr/bin/env python3
#
# Tests the expression classes.
#
# This file is part of Myokit.
# See http://myokit.org for copyright, sharing, and licensing details.
#
from __future__ import absolute_import, division
from __future__ import print_function, unicode_literals

import unittest
import myokit
import numpy as np

# Unit testing in Python 2 and 3
try:
    unittest.TestCase.assertRaisesRegex
except AttributeError:
    unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp


# Unit --> See test_units.py
# Quantity --> See test_units.py


class ExpressionTest(unittest.TestCase):
    """
    Tests various methods of the :class:`myokit.Expression` class.
    """

    def test_contains_type(self):
        # Test :meth:`Expression.contains_type`.

        self.assertTrue(myokit.Name('x').contains_type(myokit.Name))
        self.assertFalse(myokit.Name('x').contains_type(myokit.Number))
        self.assertTrue(myokit.Number(4).contains_type(myokit.Number))
        self.assertFalse(myokit.Number(4).contains_type(myokit.Name))

        e = myokit.parse_expression('x + 3')
        self.assertTrue(e.contains_type(myokit.Name))
        self.assertTrue(e.contains_type(myokit.Number))
        self.assertTrue(e.contains_type(myokit.Plus))
        self.assertFalse(e.contains_type(myokit.Minus))

        e = myokit.parse_expression('x * (x * (x * (x * (x * (1 + 1)))))')
        self.assertTrue(e.contains_type(myokit.Multiply))
        self.assertTrue(e.contains_type(myokit.Plus))
        self.assertTrue(e.contains_type(myokit.Number))
        self.assertFalse(e.contains_type(myokit.Minus))

    def test_eval(self):
        # Test :meth:`Expression.eval()`.

        # Test basic use
        e = myokit.parse_expression('1 + 1 + 1')
        self.assertEqual(e.eval(), 3)

        # Test errors
        e = myokit.parse_expression('1 / 0')
        self.assertRaises(myokit.NumericalError, e.eval)

        # Test errors-in-errors
        e = myokit.parse_expression('16^1000 / 0')
        self.assertRaisesRegex(myokit.NumericalError, 'another error', e.eval)

        # Test errors with variables
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(0)
        y.set_rhs('5 / 2')
        z.set_rhs('(x + y) / 0')
        self.assertRaisesRegex(
            myokit.NumericalError, 'c.x = 0', z.rhs().eval)
        self.assertRaisesRegex(
            myokit.NumericalError, 'c.y = 5 / 2', z.rhs().eval)

        # Test error in error with variables
        y.set_rhs('16^1000')
        self.assertRaisesRegex(
            myokit.NumericalError, 'another error', z.eval)

        # Test substitution
        y.set_rhs('5')
        z.set_rhs('x / y')
        z.rhs().eval(subst={x.lhs(): 0})
        z.rhs().eval(subst={x.lhs(): myokit.Number(1)})
        self.assertEqual(
            z.rhs().eval(
                subst={x.lhs(): myokit.parse_expression('5 * 5 * 5')}),
            25)

        # Test errors in substitution dict format
        self.assertRaisesRegex(ValueError, 'dict or None', z.rhs().eval, 2)
        self.assertRaisesRegex(ValueError, 'All keys', z.rhs().eval, {5: 1})
        self.assertRaisesRegex(
            ValueError, 'All values', z.rhs().eval, {x.lhs(): 'hello'})

        # Test if substituted Name is treated as number in error formatting
        y.set_rhs('x')
        z.set_rhs('(x + y) / 0')
        self.assertRaisesRegex(
            myokit.NumericalError, 'c.y = 3', z.rhs().eval, {y.lhs(): 3})

        # Error handling --> Correct bit should be highlighted
        z.set_rhs('(1 + 2 * (3 + sin(1 / (2 * x + (0 / 0)))))')
        with self.assertRaises(myokit.NumericalError) as e:
            z.eval()
        m = str(e.exception).splitlines()
        self.assertEqual(len(m), 7)
        self.assertEqual(m[2], '  1 + 2 * (3 + sin(1 / (2 * c.x + 0 / 0)))')
        self.assertEqual(m[3], '                                  ~~~~~')

        # Error handling --> Error when descending down a tree should be found
        y.set_rhs('3 * z')
        with self.assertRaises(myokit.NumericalError) as e:
            y.eval()
        m = str(e.exception).splitlines()
        self.assertEqual(len(m), 10)
        self.assertEqual(m[1], 'Encountered when evaluating')
        self.assertEqual(m[2], '  3 * c.z')
        self.assertEqual(m[3], 'Error located at:')
        self.assertEqual(m[4], '  c.z')
        self.assertEqual(
            m[5], 'c.z = 1 + 2 * (3 + sin(1 / (2 * c.x + 0 / 0)))')
        self.assertEqual(m[6], '                                      ~~~~~')
        self.assertEqual(m[7], 'With the following operands:')
        self.assertEqual(m[8], '  (1) 0.0')
        self.assertEqual(m[9], '  (2) 0.0')

        # Debugging name: unlinked!
        x = myokit.Name('x')
        self.assertEqual(
            x._eval_unit(myokit.UNIT_TOLERANT), None)
        self.assertEqual(
            x._eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_eval_unit_error(self):
        # Test error handling for eval_unit.

        # Incompatible units
        x = myokit.parse_expression('1 + 2 * (3 + 4 * (5 [mV] + 6 [A]))')
        with self.assertRaises(myokit.IncompatibleUnitError) as e:
            x.eval_unit()
        m = str(e.exception).splitlines()
        self.assertEqual(len(m), 4)
        self.assertEqual(m[2], '  1 + 2 * (3 + 4 * (5 [mV] + 6 [A]))')
        self.assertEqual(m[3], '                    ~~~~~~~~~~~~~~')

    def test_int_conversion(self):
        # Test conversion of expressions to int.

        x = myokit.parse_expression('1 + 2 + 3')
        self.assertEqual(int(x), 6)
        x = myokit.parse_expression('1 + 3.9')
        self.assertEqual(int(x), 4)

    def test_float_conversion(self):
        # Test conversion of expressions to float.

        x = myokit.parse_expression('1 + 2 + 3')
        self.assertEqual(int(x), 6)
        x = myokit.parse_expression('1 + 3.9')
        self.assertEqual(float(x), 4.9)

    def test_is_conditional(self):
        # Test :meth:`Expression.is_conditional().`.

        pe = myokit.parse_expression
        self.assertFalse(pe('1 + 2 + 3').is_conditional())
        self.assertTrue(pe('if(1, 0, 2)').is_conditional())
        self.assertTrue(pe('1 + if(1, 0, 2)').is_conditional())

    def test_pyfunc(self):
        # Test the pyfunc() method.

        # Note: Extensive testing happens in pywriter / numpywriter tests!
        x = myokit.parse_expression('3 * sqrt(v)')
        f = x.pyfunc(use_numpy=False)
        self.assertTrue(callable(f))
        self.assertEqual(f(4), 6)
        self.assertRaises(TypeError, f, np.array([1, 2, 3]))

        f = x.pyfunc(use_numpy=True)
        self.assertTrue(callable(f))
        self.assertEqual(f(4), 6)
        self.assertEqual(list(f(np.array([1, 4, 9]))), [3, 6, 9])

    def test_pystr(self):
        # Test the pystr() method.
        # Note: Extensive testing happens in pywriter / numpywriter tests!

        x = myokit.parse_expression('3 * sqrt(v)')
        self.assertEqual(x.pystr(use_numpy=False), '3.0 * math.sqrt(v)')
        self.assertEqual(x.pystr(use_numpy=True), '3.0 * numpy.sqrt(v)')

    def test_sequence_interface(self):
        # Tests the Expression class's sequence interface

        x = myokit.parse_expression('1 + 2')
        self.assertEqual(len(x), 2)                 # __len__
        self.assertIn(myokit.Number(1), x)          # __contains__
        self.assertIn(myokit.Number(2), x)
        self.assertEqual(x[0], myokit.Number(1))    # __getitem__
        self.assertEqual(x[1], myokit.Number(2))

        y = [op for op in x]                        # __iter__
        self.assertEqual(len(y), 2)
        self.assertIn(myokit.Number(1), y)
        self.assertIn(myokit.Number(2), y)
        self.assertEqual(y[0], myokit.Number(1))
        self.assertEqual(y[1], myokit.Number(2))

    def test_string_conversion(self):
        # Tests __str__ and __repr__

        x = myokit.Plus(myokit.Number(1), myokit.Number(2))
        self.assertEqual(str(x), '1 + 2')
        self.assertEqual(repr(x), 'myokit.Expression[1 + 2]')

    def test_tree_str(self):
        # Test :meth:`Expression.tree_str()`.
        # More extensive testing of this method should happen in the individual
        # expression tests.

        x = myokit.parse_expression('1 + 2 * 3 / 4')
        self.assertEqual(x.tree_str(), '\n'.join([
            '+',
            '  1',
            '  /',
            '    *',
            '      2',
            '      3',
            '    4',
            '',
        ]))

    def test_validation(self):
        # Test :meth:`Expression.validate()`.

        e = myokit.parse_expression('5 + 2 * exp(3 / (1 + 2))')
        e.validate()
        self.assertIsNone(e.validate())

        # Test cycles in expression tree are found (not via variables!)
        p = myokit.Plus(myokit.Number(1), myokit.Number(1))
        # Have to hack this in, since, properly used, expressions are immutable
        p._operands = (myokit.Number(2), p)
        self.assertRaisesRegex(myokit.IntegrityError, 'yclical', p.validate)

        # Wrong type operands
        # Again, need to hack this in so creation doesn't fault!
        p._operands = (myokit.Number(1), 2)
        self.assertRaisesRegex(
            myokit.IntegrityError, 'must be other Expression', p.validate)

    def test_walk(self):
        # Test :meth:`Expression.walk().

        e = myokit.parse_expression('1 / (2 + exp(3 + sqrt(4)))')
        w = list(e.walk())
        self.assertEqual(len(w), 9)
        self.assertEqual(type(w[0]), myokit.Divide)
        self.assertEqual(type(w[1]), myokit.Number)
        self.assertEqual(type(w[2]), myokit.Plus)
        self.assertEqual(type(w[3]), myokit.Number)
        self.assertEqual(type(w[4]), myokit.Exp)
        self.assertEqual(type(w[5]), myokit.Plus)
        self.assertEqual(type(w[6]), myokit.Number)
        self.assertEqual(type(w[7]), myokit.Sqrt)
        self.assertEqual(type(w[8]), myokit.Number)
        self.assertEqual(w[1].eval(), 1)
        self.assertEqual(w[3].eval(), 2)
        self.assertEqual(w[6].eval(), 3)
        self.assertEqual(w[8].eval(), 4)

        w = list(e.walk(allowed_types=[myokit.Sqrt, myokit.Exp]))
        self.assertEqual(len(w), 2)
        self.assertEqual(type(w[0]), myokit.Exp)
        self.assertEqual(type(w[1]), myokit.Sqrt)

        w = list(e.walk(allowed_types=myokit.Exp))
        self.assertEqual(len(w), 1)
        self.assertEqual(type(w[0]), myokit.Exp)


class NumberTest(unittest.TestCase):
    """
    Tests myokit.Number.
    """

    def test_basic(self):
        # Test construction, other basics.

        # Test myokit.Number creation and representation
        x = myokit.Number(-4.0)
        self.assertEqual(str(x), '-4')
        x = myokit.Number(4.0)
        self.assertEqual(str(x), '4')
        y = myokit.Number(4)
        self.assertEqual(str(y), '4')
        self.assertEqual(x, y)
        self.assertFalse(x is y)
        x = myokit.Number(4.01)
        self.assertEqual(str(x), '4.01')
        x = myokit.Number(-4.01)
        self.assertEqual(str(x), '-4.01')
        x = myokit.Number('-4e9')
        self.assertEqual(str(x), '-4.00000000000000000e9')
        x = myokit.Number('4e+09')
        self.assertEqual(str(x), ' 4.00000000000000000e9')
        x = myokit.Number('-4e+00')
        self.assertEqual(str(x), '-4')
        x = myokit.Number('4e-05')
        self.assertEqual(str(x), '4e-5')
        x = myokit.Number('4e+15')
        self.assertEqual(float(x), 4e15)
        x = myokit.Number(4, myokit.Unit.parse_simple('pF'))
        self.assertEqual(str(x), '4 [pF]')
        x = myokit.Number(-3, myokit.Unit.parse_simple('pF'))
        self.assertEqual(str(x), '-3 [pF]')

        # Test unit conversion
        x = myokit.Number('2000', myokit.units.pF)
        y = x.convert('nF')
        self.assertEqual(y.eval(), 2)
        self.assertEqual(str(y), '2 [nF]')
        self.assertEqual(y.unit(), myokit.Unit.parse_simple('nF'))
        a = y.convert('uF')
        b = x.convert('uF')
        self.assertEqual(a, b)
        self.assertRaises(myokit.IncompatibleUnitError, x.convert, 'A')

        # Test properties
        x = myokit.Number(2)
        self.assertFalse(x.is_conditional())
        self.assertTrue(x.is_constant())
        self.assertTrue(x.is_literal())
        self.assertFalse(x.is_state_value())

        # Test construction
        # Second argument must be a unit, if given
        myokit.Number(3, 'kg')
        self.assertRaisesRegex(ValueError, 'Unit', myokit.Number, 3, 1)
        # Construction from quantity
        q = myokit.Quantity(3, 'kg')
        myokit.Number(q)
        self.assertEqual(q.unit(), myokit.parse_unit('kg'))
        self.assertRaisesRegex(ValueError, 'unit', myokit.Number, q, 'kg')

    def test_bracket(self):
        # Test Number.bracket().
        # Never needs a bracket
        x = myokit.Number(2)
        self.assertFalse(x.bracket())

        # Doesn't have an operand
        self.assertRaises(ValueError, x.bracket, myokit.Number(2))

    def test_clone(self):
        # Test Number.clone().

        x = myokit.Number(2)
        y = x.clone()
        self.assertIsNot(x, y)
        self.assertEqual(x, y)

        # With substitution
        z = myokit.Number(10)
        y = x.clone(subst={x: z})
        self.assertEqual(y, z)

        # Test that substitution changes references
        # Note: This should follow automatically from set_rhs() implementation
        # and fact that expressions are immutable.
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs(2)
        y = c.add_variable('y')
        y.set_rhs('3 * x')
        self.assertIn(x.lhs(), y.rhs().references())
        self.assertIn(x, y.refs_to())
        self.assertIn(y, x.refs_by())
        y.set_rhs(y.rhs().clone(subst={x.lhs(): myokit.Number(4)}))
        self.assertNotIn(x.lhs(), y.rhs().references())
        self.assertNotIn(x, y.refs_to())
        self.assertNotIn(y, x.refs_by())

    def test_eval(self):
        # Test evaluation (with single precision).

        x = myokit.Number(2)
        self.assertEqual(type(x.eval()), float)
        self.assertEqual(
            type(x.eval(precision=myokit.SINGLE_PRECISION)), np.float32)

    def test_eval_unit(self):
        # Test Number eval_unit.

        # Test in tolerant mode
        x = myokit.Number(3)
        self.assertEqual(x.eval_unit(), None)
        y = myokit.Number(3, myokit.units.ampere)
        self.assertEqual(y.eval_unit(), myokit.units.ampere)

        # Test in strict mode
        self.assertEqual(
            x.eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(y.eval_unit(myokit.UNIT_STRICT), myokit.units.ampere)

    def test_tree_str(self):
        # Test Number.tree_str()

        # Test simple
        x = myokit.Number(1)
        self.assertEqual(x.tree_str(), '1\n')

        # Test with spaces
        e = myokit.Plus(x, myokit.Number(-2))
        self.assertEqual(e.tree_str(), '+\n  1\n  -2\n')


class NameTest(unittest.TestCase):
    """
    Tests myokit.Name.
    """

    def test_basics(self):
        # Test creation, representation,

        model = myokit.Model()
        component = model.add_component('c')
        xvar = component.add_variable('x')
        xvar.set_rhs('15')
        yvar = component.add_variable('y')
        yvar.set_rhs('3 * x ')
        zvar = component.add_variable('z')
        zvar.set_rhs('2 + y + x')

        x = myokit.Name(xvar)
        y = myokit.Name(yvar)
        z = myokit.Name(zvar)

        self.assertEqual(x.code(), 'c.x')

        # Test rhs
        # Name of non-state: rhs() should be the associated variable's rhs
        self.assertEqual(x.rhs(), myokit.Number(15))
        # Name of state: rhs() should be the initial value (since this is the
        # value of the variable).
        xvar.promote(12)
        self.assertEqual(x.rhs(), myokit.Number(12))
        # Invalid variable:
        a = myokit.Name('test')
        self.assertRaises(Exception, a.rhs)

        # Test validation
        x.validate()
        y.validate()
        z.validate()
        a = myokit.Name('test')
        self.assertRaises(myokit.IntegrityError, a.validate)

        # Test var()
        self.assertEqual(x.var(), xvar)
        self.assertEqual(y.var(), yvar)
        self.assertEqual(z.var(), zvar)

        # Test properties
        # State x
        self.assertFalse(x.is_conditional())
        self.assertFalse(x.is_constant())
        self.assertFalse(x.is_literal())
        self.assertTrue(x.is_state_value())

        # State-dependent variable y
        self.assertFalse(y.is_conditional())
        self.assertFalse(y.is_constant())
        self.assertFalse(y.is_literal())
        self.assertFalse(y.is_state_value())

        # Non-state x
        xvar.demote()
        self.assertFalse(x.is_conditional())
        self.assertTrue(x.is_constant())
        self.assertFalse(x.is_literal())    # A name is never a literal!
        self.assertFalse(x.is_state_value())

        # (Non-state)-dependent variable y
        self.assertFalse(y.is_conditional())
        self.assertTrue(y.is_constant())
        self.assertFalse(y.is_literal())
        self.assertFalse(y.is_state_value())

    def test_bracket(self):
        # Test Name.bracket().
        # Never needs a bracket
        x = myokit.Name('hi')
        self.assertFalse(x.bracket())

        # Doesn't have an operand
        self.assertRaises(ValueError, x.bracket, myokit.Number(2))

    def test_clone(self):
        # Test Name.clone().
        m = myokit.Model()
        c = m.add_component('c')
        vx = c.add_variable('x')
        vy = c.add_variable('y')
        vz = c.add_variable('z')
        vx.set_rhs(1)
        vy.set_rhs('2 * x')
        vz.set_rhs('2 * x + y')
        x = myokit.Name(vx)
        y = myokit.Name(vy)
        z = myokit.Name(vz)

        # Test clone
        a = x.clone()
        self.assertEqual(x, a)
        a = z.clone()
        self.assertEqual(z, a)

        # With substitution (handled in Name)
        a = x.clone(subst={x: y})
        self.assertEqual(y, a)
        a = x.clone()
        self.assertEqual(x, a)

        # With expansion (handled in Name)
        a = z.clone()
        self.assertEqual(z, a)
        a = z.clone(expand=True)
        self.assertTrue(a.is_literal())
        self.assertFalse(z.is_literal())
        self.assertEqual(z.eval(), a.eval())

        # With expansion but retention of selected variables (handled in Name)
        a = z.clone(expand=True, retain=[x])
        self.assertNotEqual(a, z)
        self.assertFalse(a.is_literal())
        self.assertEqual(z.eval(), a.eval())

        # Few options for how to specify x:
        b = z.clone(expand=True, retain=['c.x'])
        self.assertEqual(a, b)
        b = z.clone(expand=True, retain=[vx])
        self.assertEqual(a, b)

    def test_eval_unit(self):
        # Test Name eval_unit.

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs(3)
        y = c.add_variable('y')
        y.set_rhs(2)
        y.set_unit(myokit.units.Newton)

        # At this point, x and y both have a unitless rhs (despite y having a
        # variable unit)

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), None)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

        # Now have x mention y in its rhs
        x.set_rhs('y')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), myokit.units.Newton)
        self.assertEqual(y.rhs().eval_unit(), None)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_rhs(self):
        # Test Name.rhs().

        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('3 + 2')

        x = myokit.Name(x)
        self.assertEqual(x.rhs().eval(), 5)

    def test_tree_str(self):
        # Test Name.tree_str()

        # Test simple
        x = myokit.Name('y')
        self.assertEqual(x.tree_str(), 'y\n')

        # Test with spaces
        e = myokit.Plus(x, x)
        self.assertEqual(e.tree_str(), '+\n  y\n  y\n')

    def test_values(self):
        # Test with values other than Variables

        # Special case: string
        x = myokit.Name('this is ok')
        self.assertEqual(x.code(), 'str:this is ok')

        # All other values (this allows e.g. CellML expressions to be created)
        x = myokit.Name(12.3)
        self.assertEqual(x.code(), '12.3')


class DerivativeTest(unittest.TestCase):
    """
    Tests myokit.Derivative.
    """
    def test_basic(self):
        # Test creation.

        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs(3)
        x.promote(0)
        y = c.add_variable('y')
        y.set_rhs(2)

        # Derivative of state
        d = myokit.Derivative(myokit.Name(x))
        d.validate()

        # Derivative of non-state: allowed during model building, but doesn't
        # validate
        d = myokit.Derivative(myokit.Name(y))
        self.assertRaisesRegex(
            myokit.IntegrityError, 'only be defined for state', d.validate)

        # Derivative of something other than a name: never allowed
        self.assertRaisesRegex(
            myokit.IntegrityError, 'named variables', myokit.Derivative,
            myokit.Number(1))

    def test_bracket(self):
        # Test Derivative.bracket()
        x = myokit.Derivative(myokit.Name('x'))
        self.assertFalse(x.bracket(myokit.Name('x')))
        self.assertRaises(ValueError, x.bracket, myokit.Number(1))

    def test_clone(self):
        # Test Derivative.clone().
        x = myokit.Derivative(myokit.Name('x'))
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Derivative(myokit.Name('z'))
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        i = myokit.Name('i')
        j = myokit.Name('j')
        x = myokit.Derivative(i)
        y = x.clone(subst={i: j})
        self.assertIsNot(y, x)
        self.assertNotEqual(y, x)
        self.assertEqual(y, myokit.Derivative(j))

    def test_eval_unit(self):
        # Test Derivative.eval_unit()
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        t = c.add_variable('t')
        t.set_rhs('0')
        t.set_binding('time')
        x = c.add_variable('x')
        x.set_rhs('(10 - x) / 100')
        x.promote(0)

        # Get derivative object
        d = x.lhs()

        s = myokit.UNIT_STRICT

        # No units set anywhere: dimensionless
        self.assertEqual(d.eval_unit(), None)
        self.assertEqual(d.eval_unit(s), myokit.units.dimensionless)

        # Time has a unit
        t.set_unit(myokit.units.second)
        self.assertEqual(d.eval_unit(), 1 / myokit.units.second)
        self.assertEqual(d.eval_unit(s), 1 / myokit.units.second)

        # Both have a unit
        x.set_unit(myokit.units.volt)
        self.assertEqual(
            d.eval_unit(), myokit.units.volt / myokit.units.second)
        self.assertEqual(
            d.eval_unit(s), myokit.units.volt / myokit.units.second)

        # Time has no unit
        t.set_unit(None)
        self.assertEqual(d.eval_unit(), myokit.units.volt)
        self.assertEqual(d.eval_unit(s), myokit.units.volt)

    def test_rhs(self):
        # Test Derivative.rhs()
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('(10 - x) / 100')
        x.promote(0)

        # Get derivative object
        d = x.lhs()
        self.assertEqual(d.rhs(), x.rhs())

    def test_tree_str(self):
        # Test Derivative.tree_str()

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('(10 - x) / 100')
        x.promote(0)

        # Get derivative object
        d = x.lhs()

        # Test simple
        self.assertEqual(d.tree_str(), 'dot(c.x)\n')

        # Test with spaces
        e = myokit.Plus(d, d)
        self.assertEqual(e.tree_str(), '+\n  dot(c.x)\n  dot(c.x)\n')


class PrefixPlusTest(unittest.TestCase):
    """
    Tests myokit.PrefixPlus.
    """
    def test_clone(self):
        # Test PrefixPlus.clone().
        x = myokit.PrefixPlus(myokit.Number(3))
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.PrefixPlus(myokit.Number(4))
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        i = myokit.Number(1)
        j = myokit.Number(2)
        x = myokit.PrefixPlus(i)
        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.PrefixPlus(j))

    def test_bracket(self):
        # Test PrefixPlus.bracket().
        i = myokit.Number(1)
        x = myokit.PrefixPlus(i)
        self.assertFalse(x.bracket(i))
        i = myokit.Plus(myokit.Number(1), myokit.Number(2))
        x = myokit.PrefixPlus(i)
        self.assertTrue(x.bracket(i))
        self.assertRaises(ValueError, x.bracket, myokit.Number(1))

    def test_eval(self):
        # Test PrefixPlus evaluation.
        x = myokit.PrefixPlus(myokit.Number(2))
        self.assertEqual(x.eval(), 2)

    def test_eval_unit(self):
        # Test PrefixPlus.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('+(3)')
        y = c.add_variable('y')
        y.set_rhs('+(2 [N])')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), myokit.units.Newton)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)

    def test_tree_str(self):
        # Test PrefixPlus.tree_str()

        # Test simple
        x = myokit.PrefixPlus(myokit.Number(1))
        self.assertEqual(x.tree_str(), '+\n  1\n')

        # Test with spaces
        y = myokit.Plus(
            myokit.PrefixPlus(myokit.Number(-1)),
            myokit.PrefixPlus(myokit.Number(2)))
        self.assertEqual(y.tree_str(), '+\n  +\n    -1\n  +\n    2\n')


class PrefixMinusTest(unittest.TestCase):
    """
    Tests myokit.PrefixMinus.
    """
    def test_clone(self):
        # Test PrefixMinus.clone().
        x = myokit.PrefixMinus(myokit.Number(3))
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.PrefixMinus(myokit.Number(4))
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        i = myokit.Number(1)
        j = myokit.Number(2)
        x = myokit.PrefixMinus(i)
        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.PrefixMinus(j))

    def test_bracket(self):
        # Test PrefixMinus.bracket().
        i = myokit.Number(1)
        x = myokit.PrefixMinus(i)
        self.assertFalse(x.bracket(i))
        i = myokit.Plus(myokit.Number(1), myokit.Number(2))
        x = myokit.PrefixMinus(i)
        self.assertTrue(x.bracket(i))
        self.assertRaises(ValueError, x.bracket, myokit.Number(1))

    def test_eval(self):
        # Test PrefixMinus evaluation.

        x = myokit.PrefixMinus(myokit.Number(2))
        self.assertEqual(x.eval(), -2)

    def test_eval_unit(self):
        # Test PrefixMinus.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('-(3)')
        y = c.add_variable('y')
        y.set_rhs('-(2 [N])')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), myokit.units.Newton)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)

    def test_tree_str(self):
        # Test PrefixMinus.tree_str()
        # Test simple
        x = myokit.PrefixMinus(myokit.Number(1))
        self.assertEqual(x.tree_str(), '-\n  1\n')

        # Test with spaces
        y = myokit.Plus(
            myokit.PrefixMinus(myokit.Number(1)),
            myokit.PrefixMinus(myokit.Number(-2)))
        self.assertEqual(y.tree_str(), '+\n  -\n    1\n  -\n    -2\n')


class PlusTest(unittest.TestCase):
    """
    Tests myokit.Plus.
    """
    def test_clone(self):
        # Test Plus.clone().
        i = myokit.Number(3)
        j = myokit.Number(4)
        x = myokit.Plus(i, j)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Plus(j, i)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Plus(j, j))
        y = x.clone(subst={j: i})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Plus(i, i))

    def test_bracket(self):
        # Test Plus.bracket().
        i = myokit.Number(1)
        j = myokit.parse_expression('1 + 2')
        x = myokit.Plus(i, j)
        self.assertFalse(x.bracket(i))
        self.assertTrue(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

    def test_eval(self):
        # Test Plus evaluation.

        x = myokit.Plus(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.eval(), 3)
        x = myokit.Plus(myokit.Number(1), myokit.PrefixMinus(myokit.Number(2)))
        self.assertEqual(x.eval(), -1)

    def test_eval_unit(self):
        # Test Plus.eval_unit().
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Plus(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        y.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        x.set_unit(None)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

        # Tokens are used in IncompatibleUnitError messages
        m = myokit.parse_model('\n'.join([
            '[[model]]',
            '[a]',
            't = 1 [ms] + 1 [mV]',
            '    in [ms]',
            '    bind time',
        ]))
        try:
            m.check_units(myokit.UNIT_STRICT)
        except myokit.IncompatibleUnitError as e:
            self.assertIn('on line 3', str(e))
            token = e.token()
            self.assertIsNotNone(token)
            self.assertEqual(token[2], 3)
            self.assertEqual(token[3], 11)

    def test_tree_str(self):
        # Test Plus.tree_str().
        # Test simple
        x = myokit.Plus(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '+\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  +\n    1\n    2\n')
        x = myokit.parse_expression('1 + (2 + 3)')
        self.assertEqual(x.tree_str(), '+\n  1\n  +\n    2\n    3\n')


class MinusTest(unittest.TestCase):
    """
    Tests myokit.Minus.
    """
    def test_eval(self):
        # Test Minus evaluation.

        x = myokit.Minus(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.eval(), -1)

    def test_eval_unit(self):
        # Test Minus.eval_unit().
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Minus(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        y.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        x.set_unit(None)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Minus.tree_str().
        # Test simple
        x = myokit.Minus(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '-\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  -\n    1\n    2\n')
        x = myokit.parse_expression('1 - (2 - 3)')
        self.assertEqual(x.tree_str(), '-\n  1\n  -\n    2\n    3\n')


class MultiplyTest(unittest.TestCase):
    """
    Tests myokit.Multiply.
    """
    def test_eval(self):
        # Test Multiply evaluation.

        x = myokit.Multiply(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.eval(), 2)

    def test_eval_unit(self):
        # Test Multiply.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Multiply(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(), myokit.units.volt * myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (where None becomes dimensionless)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.volt * myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Multiply.tree_str().
        # Test simple
        x = myokit.Multiply(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '*\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  *\n    1\n    2\n')
        x = myokit.parse_expression('1 * (2 * 3)')
        self.assertEqual(x.tree_str(), '*\n  1\n  *\n    2\n    3\n')


class DivideTest(unittest.TestCase):
    """
    Tests myokit.Divide.
    """
    def test_tree_str(self):
        # Test Divide.tree_str().
        # Test simple
        x = myokit.Divide(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '/\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  /\n    1\n    2\n')
        x = myokit.parse_expression('1 / (2 / 3)')
        self.assertEqual(x.tree_str(), '/\n  1\n  /\n    2\n    3\n')

    def test_eval(self):
        # Test Divide evaluation.
        x = myokit.Divide(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.eval(), 0.5)

    def test_eval_unit(self):
        # Test Divide.eval_unit().
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Divide(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(), myokit.units.volt / myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), 1 / myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (where None becomes dimensionless)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.volt / myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            1 / myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)


class QuotientTest(unittest.TestCase):
    """
    Tests myokit.Quotient.
    """
    def test_eval(self):
        # Test Quotient evaluation.

        x = myokit.Quotient(myokit.Number(7), myokit.Number(2))
        self.assertEqual(x.eval(), 3.0)

    def test_eval_unit(self):
        # Test Quotient.eval_unit().
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Quotient(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(), myokit.units.volt / myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), 1 / myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (where None becomes dimensionless)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.volt / myokit.units.meter)
        x.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            1 / myokit.units.meter)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Quotient.tree_str().
        # Test simple
        x = myokit.Quotient(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '//\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  //\n    1\n    2\n')
        x = myokit.parse_expression('1 // (2 // 3)')
        self.assertEqual(x.tree_str(), '//\n  1\n  //\n    2\n    3\n')


class RemainderTest(unittest.TestCase):
    """
    Tests myokit.Remainder.
    """
    def test_eval(self):
        # Test Divide evaluation.

        x = myokit.Remainder(myokit.Number(7), myokit.Number(4))
        self.assertEqual(x.eval(), 3.0)

    def test_eval_unit(self):
        # Test Remainder.eval_unit().
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(1)
        z.set_rhs(myokit.Remainder(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(), myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (where None becomes dimensionless)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.volt)
        y.set_unit(myokit.units.meter)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT),
            myokit.units.dimensionless)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Remainder.tree_str().
        # Test simple
        x = myokit.Remainder(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '%\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  %\n    1\n    2\n')
        x = myokit.parse_expression('1 % (2 % 3)')
        self.assertEqual(x.tree_str(), '%\n  1\n  %\n    2\n    3\n')


class PowerTest(unittest.TestCase):
    """
    Tests myokit.Power.
    """
    def test_clone(self):
        # Test Power.clone().
        i = myokit.Number(3)
        j = myokit.Number(4)
        x = myokit.Power(i, j)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Power(j, i)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Power(j, j))
        y = x.clone(subst={j: i})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Power(i, i))

    def test_bracket(self):
        # Test Power.bracket().
        i = myokit.Number(1)
        j = myokit.parse_expression('1 + 2')
        x = myokit.Power(i, j)
        self.assertFalse(x.bracket(i))
        self.assertTrue(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

    def test_eval(self):
        # Test Power evaluation.

        x = myokit.Power(myokit.Number(2), myokit.Number(3))
        self.assertEqual(x.eval(), 8)
        x = myokit.Power(
            myokit.Number(2), myokit.PrefixMinus(myokit.Number(1)))
        self.assertEqual(x.eval(), 0.5)

    def test_eval_unit(self):
        # Test Power.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(2)
        z.set_rhs(myokit.Power(x.lhs(), y.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt ** 2)
        y.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt ** 2)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.volt ** 2)
        y.set_unit(myokit.units.volt)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        x.set_unit(None)
        self.assertRaises(
            myokit.IncompatibleUnitError,
            z.rhs().eval_unit, myokit.UNIT_STRICT)
        y.set_unit(None)
        self.assertEqual(
            z.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Power.tree_str().

        # Test simple
        x = myokit.Power(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '^\n  1\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  ^\n    1\n    2\n')
        x = myokit.parse_expression('1 ^ (2 ^ 3)')
        self.assertEqual(x.tree_str(), '^\n  1\n  ^\n    2\n    3\n')


class SqrtTest(unittest.TestCase):
    """
    Tests myokit.Sqrt.
    """
    def test_creation(self):
        # Test Sqrt creation.
        myokit.Sqrt(myokit.Number(1))
        self.assertRaisesRegex(
            myokit.IntegrityError, 'wrong number', myokit.Sqrt,
            myokit.Number(1), myokit.Number(2))

    def test_clone(self):
        # Test Sqrt.clone().
        i = myokit.Number(3)
        j = myokit.Number(10)
        x = myokit.Sqrt(i)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Sqrt(j)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, z)

    def test_bracket(self):
        # Test Sqrt.bracket().
        i = myokit.Number(1)
        j = myokit.parse_expression('1 + 2')
        x = myokit.Sqrt(i)
        self.assertFalse(x.bracket(i))
        x = myokit.Sqrt(j)
        self.assertFalse(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

    def test_eval(self):
        # Test Sqrt evaluation.
        x = myokit.Sqrt(myokit.Number(9))
        self.assertEqual(x.eval(), 3)

    def test_eval_unit(self):
        # Test Sqrt.eval_unit().
        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        z = c.add_variable('z')
        x.set_rhs(1)
        z.set_rhs(myokit.Sqrt(x.lhs()))

        # Test in tolerant mode
        #self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt**0.5)
        x.set_unit(myokit.units.volt ** 2)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.volt**0.5)
        x.set_unit(myokit.units.volt ** 2)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.volt)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Sqrt.tree_str().
        # Test simple
        x = myokit.Sqrt(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'sqrt\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  sqrt\n    2\n')
        x = myokit.parse_expression('sqrt(1 + sqrt(2))')
        self.assertEqual(x.tree_str(), 'sqrt\n  +\n    1\n    sqrt\n      2\n')


class ExpTest(unittest.TestCase):
    """
    Tests myokit.Exp.
    """
    def test_creation(self):
        # Test Exp creation.
        myokit.Exp(myokit.Number(1))
        self.assertRaisesRegex(
            myokit.IntegrityError, 'wrong number', myokit.Exp,
            myokit.Number(1), myokit.Number(2))

    def test_clone(self):
        # Test Exp.clone().
        i = myokit.Number(3)
        j = myokit.Number(10)
        x = myokit.Exp(i)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Exp(j)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, z)

    def test_bracket(self):
        # Test Exp.bracket().
        i = myokit.Number(1)
        j = myokit.parse_expression('1 + 2')
        x = myokit.Exp(i)
        self.assertFalse(x.bracket(i))
        x = myokit.Exp(j)
        self.assertFalse(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

    def test_eval(self):
        # Test Exp.eval().
        x = myokit.Exp(myokit.Number(9))
        self.assertEqual(x.eval(), np.exp(9))

    def test_eval_unit(self):
        # Test Exp.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        z = c.add_variable('z')
        x.set_rhs(1)
        z.set_rhs(myokit.Exp(x.lhs()))

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless',
            z.rhs().eval_unit, s)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Exp.tree_str().

        # Test simple
        x = myokit.Exp(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'exp\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  exp\n    2\n')
        x = myokit.parse_expression('exp(1 + exp(2))')
        self.assertEqual(x.tree_str(), 'exp\n  +\n    1\n    exp\n      2\n')


class LogTest(unittest.TestCase):
    """
    Tests myokit.Log.
    """
    def test_creation(self):
        # Test Log creation.
        myokit.Log(myokit.Number(1))
        myokit.Log(myokit.Number(1), myokit.Number(2))
        self.assertRaisesRegex(
            myokit.IntegrityError, 'wrong number', myokit.Log,
            myokit.Number(1), myokit.Number(2), myokit.Number(3))

    def test_clone(self):
        # Test Log.clone().

        # Test with one operand
        i = myokit.Number(3)
        j = myokit.Number(10)
        x = myokit.Log(i)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Log(j)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, z)

        # Test with two operands
        x = myokit.Log(i, j)
        y = x.clone()
        self.assertIsNot(y, x)
        self.assertEqual(y, x)

        z = myokit.Log(j, i)
        y = x.clone(subst={x: z})
        self.assertIsNot(y, x)
        self.assertIs(y, z)
        self.assertNotEqual(y, x)
        self.assertEqual(y, z)

        y = x.clone(subst={i: j})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Log(j, j))
        y = x.clone(subst={j: i})
        self.assertIsNot(x, y)
        self.assertNotEqual(x, y)
        self.assertEqual(y, myokit.Log(i, i))

    def test_bracket(self):
        # Test Log.bracket().
        i = myokit.Number(1)
        j = myokit.parse_expression('1 + 2')

        # Test with one operand
        x = myokit.Log(i)
        self.assertFalse(x.bracket(i))
        x = myokit.Log(j)
        self.assertFalse(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

        # Test with two operands
        x = myokit.Log(i, j)
        self.assertFalse(x.bracket(i))
        self.assertFalse(x.bracket(j))
        self.assertRaises(ValueError, x.bracket, myokit.Number(3))

    def test_eval(self):
        # Test Exp.eval().
        # One argument
        x = myokit.Log(myokit.Number(9))
        self.assertEqual(x.eval(), np.log(9))

        # Two arguments
        x = myokit.Log(myokit.Number(9), myokit.Number(5))
        self.assertEqual(x.eval(), np.log(9) / np.log(5))

    def test_eval_unit(self):
        # Test Log.eval_unit().

        # Create mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        y = c.add_variable('y')
        z = c.add_variable('z')
        x.set_rhs(1)
        y.set_rhs(2)

        # Single operand
        z.set_rhs(myokit.Log(x.lhs()))

        # Test in tolerant mode (single operand)
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (single operand)
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless',
            z.rhs().eval_unit, s)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

        # Double operand
        z.set_rhs(myokit.Log(x.lhs(), y.lhs()))

        # Test in tolerant mode (double operand)
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        y.set_unit(myokit.units.volt)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode (double operand)
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.volt)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless',
            z.rhs().eval_unit, s)
        y.set_unit(myokit.units.volt)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless',
            z.rhs().eval_unit, s)
        x.set_unit(None)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless',
            z.rhs().eval_unit, s)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Log.tree_str().

        # Test simple
        x = myokit.Log(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'log\n  2\n')

        # Test with spaces
        x = myokit.PrefixMinus(x)
        self.assertEqual(x.tree_str(), '-\n  log\n    2\n')
        x = myokit.parse_expression('log(log(1, 2))')
        self.assertEqual(x.tree_str(), 'log\n  log\n    1\n    2\n')


class Log10Test(unittest.TestCase):
    """
    Tests myokit.Log10.
    """
    def test_eval(self):
        # Test Log10.eval().
        x = myokit.Log10(myokit.Number(9))
        self.assertEqual(x.eval(), np.log10(9))

    def test_tree_str(self):
        # Test Log10.tree_str().
        x = myokit.Log10(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'log10\n  2\n')


class SinTest(unittest.TestCase):
    """
    Tests myokit.Sin.
    """
    def test_eval(self):
        # Test Sin.eval().
        x = myokit.Sin(myokit.Number(9))
        self.assertEqual(x.eval(), np.sin(9))

    def test_tree_str(self):
        # Test Sin.tree_str().
        x = myokit.Sin(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'sin\n  2\n')


class CosTest(unittest.TestCase):
    """
    Tests myokit.Cos.
    """
    def test_eval(self):
        # Test Cos.eval().
        x = myokit.Cos(myokit.Number(9))
        self.assertEqual(x.eval(), np.cos(9))

    def test_tree_str(self):
        # Test Cos.tree_str().
        x = myokit.Cos(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'cos\n  2\n')


class TanTest(unittest.TestCase):
    """
    Tests myokit.Tan.
    """
    def test_eval(self):
        # Test Tan.eval().
        x = myokit.Tan(myokit.Number(9))
        self.assertEqual(x.eval(), np.tan(9))

    def test_tree_str(self):
        # Test Tan.tree_str().
        x = myokit.Tan(myokit.Number(2))
        self.assertEqual(x.tree_str(), 'tan\n  2\n')


class ASinTest(unittest.TestCase):
    """
    Tests myokit.ASin.
    """
    def test_eval(self):
        # Test ASin.eval().
        x = myokit.ASin(myokit.Number(0.9))
        self.assertEqual(x.eval(), np.arcsin(0.9))

    def test_tree_str(self):
        # Test ASin.tree_str().
        x = myokit.ASin(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'asin\n  0.5\n')


class ACosTest(unittest.TestCase):
    """
    Tests myokit.ACos.
    """
    def test_eval(self):
        # Test ACos.eval().
        x = myokit.ACos(myokit.Number(0.9))
        self.assertEqual(x.eval(), np.arccos(0.9))

    def test_tree_str(self):
        # Test ACos.tree_str().
        x = myokit.ACos(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'acos\n  0.5\n')


class ATanTest(unittest.TestCase):
    """
    Tests myokit.ATan.
    """
    def test_eval(self):
        # Test ATan.eval().
        x = myokit.ATan(myokit.Number(0.9))
        self.assertEqual(x.eval(), np.arctan(0.9))

    def test_tree_str(self):
        # Test ATan.tree_str().
        x = myokit.ATan(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'atan\n  0.5\n')


class FloorTest(unittest.TestCase):
    """
    Tests myokit.Floor.
    """
    def test_eval(self):
        # Test Floor.eval().
        x = myokit.Floor(myokit.Number(0.9))
        self.assertEqual(x.eval(), 0)

    def test_eval_unit(self):
        # Test Floor.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('floor(3)')
        y = c.add_variable('y')
        y.set_rhs('floor(2 [N])')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), myokit.units.Newton)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)

    def test_tree_str(self):
        # Test Floor.tree_str().
        x = myokit.Floor(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'floor\n  0.5\n')


class CeilTest(unittest.TestCase):
    """
    Tests myokit.Ceil.
    """
    def test_eval(self):
        # Test Ceil.eval().
        x = myokit.Ceil(myokit.Number(0.9))
        self.assertEqual(x.eval(), 1)

    def test_eval_unit(self):
        # Test Ceil.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('ceil(3)')
        y = c.add_variable('y')
        y.set_rhs('ceil(2 [N])')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), myokit.units.Newton)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)

    def test_tree_str(self):
        # Test Ceil.tree_str().
        x = myokit.Ceil(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'ceil\n  0.5\n')


class AbsTest(unittest.TestCase):
    """
    Tests myokit.Abs.
    """
    def test_eval(self):
        # Test Abs.eval().
        x = myokit.Abs(myokit.Number(0.9))
        self.assertEqual(x.eval(), 0.9)
        x = myokit.Abs(myokit.Number(-0.9))
        self.assertEqual(x.eval(), 0.9)

    def test_eval_unit(self):
        # Test Abs.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('abs(3)')
        y = c.add_variable('y')
        y.set_rhs('abs(2 [N])')

        # Test in tolerant mode
        self.assertEqual(x.rhs().eval_unit(), None)
        self.assertEqual(y.rhs().eval_unit(), myokit.units.Newton)

        # Test in strict mode
        self.assertEqual(
            x.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.dimensionless)
        self.assertEqual(
            y.rhs().eval_unit(myokit.UNIT_STRICT), myokit.units.Newton)

    def test_tree_str(self):
        # Test Abs.tree_str().
        x = myokit.Abs(myokit.Number(0.5))
        self.assertEqual(x.tree_str(), 'abs\n  0.5\n')


class EqualTest(unittest.TestCase):
    """
    Tests myokit.Equal.
    """
    def test_eval(self):
        # Test Equal.eval().
        x = myokit.Equal(myokit.Number(1), myokit.Number(1))
        self.assertTrue(x.eval())
        x = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertFalse(x.eval())

    def test_eval_unit(self):
        # Test Equal.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('3')
        y = c.add_variable('y')
        y.set_rhs('3')
        z = c.add_variable('z')
        z.set_rhs('x == y')

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.ampere)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        y.set_unit(myokit.units.ampere)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        y.set_unit(myokit.units.volt)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'equal units', z.rhs().eval_unit)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'equal units', z.rhs().eval_unit, s)
        y.set_unit(myokit.units.ampere)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        y.set_unit(myokit.units.volt)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'equal units', z.rhs().eval_unit)
        x.set_unit(None)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'equal units', z.rhs().eval_unit, s)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Equal.tree_str().
        x = myokit.Equal(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '==\n  1\n  2\n')
        x = myokit.Plus(myokit.Number(3), x)
        self.assertEqual(x.tree_str(), '+\n  3\n  ==\n    1\n    2\n')


class NotEqualTest(unittest.TestCase):
    """
    Tests myokit.NotEqual.
    """
    def test_eval(self):
        # Test NotEqual.eval().
        x = myokit.NotEqual(myokit.Number(1), myokit.Number(1))
        self.assertFalse(x.eval())
        x = myokit.NotEqual(myokit.Number(1), myokit.Number(2))
        self.assertTrue(x.eval())

    def test_tree_str(self):
        # Test NotEqual.tree_str().
        x = myokit.NotEqual(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '!=\n  1\n  2\n')
        x = myokit.Plus(myokit.Number(3), x)
        self.assertEqual(x.tree_str(), '+\n  3\n  !=\n    1\n    2\n')


class MoreTest(unittest.TestCase):
    """
    Tests myokit.More.
    """
    def test_eval(self):
        # Test More.eval().
        x = myokit.More(myokit.Number(1), myokit.Number(1))
        self.assertFalse(x.eval())
        x = myokit.More(myokit.Number(3), myokit.Number(2))
        self.assertTrue(x.eval())

    def test_tree_str(self):
        # Test More.tree_str().
        x = myokit.More(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '>\n  1\n  2\n')
        x = myokit.Plus(myokit.Number(3), x)
        self.assertEqual(x.tree_str(), '+\n  3\n  >\n    1\n    2\n')


class LessTest(unittest.TestCase):
    """
    Tests myokit.Less.
    """
    def test_eval(self):
        # Test Less.eval().
        x = myokit.Less(myokit.Number(1), myokit.Number(1))
        self.assertFalse(x.eval())
        x = myokit.Less(myokit.Number(1), myokit.Number(2))
        self.assertTrue(x.eval())

    def test_tree_str(self):
        # Test Less.tree_str().
        x = myokit.Less(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '<\n  1\n  2\n')
        x = myokit.Plus(myokit.Number(3), x)
        self.assertEqual(x.tree_str(), '+\n  3\n  <\n    1\n    2\n')


class MoreEqualTest(unittest.TestCase):
    """
    Tests myokit.MoreEqual.
    """
    def test_eval(self):
        # Test MoreEqual.eval().
        x = myokit.MoreEqual(myokit.Number(1), myokit.Number(1))
        self.assertTrue(x.eval())
        x = myokit.MoreEqual(myokit.Number(3), myokit.Number(2))
        self.assertTrue(x.eval())
        x = myokit.MoreEqual(myokit.Number(1), myokit.Number(2))
        self.assertFalse(x.eval())

    def test_tree_str(self):
        # Test MoreEqual.tree_str().
        x = myokit.MoreEqual(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '>=\n  1\n  2\n')
        x = myokit.Plus(myokit.Number(3), x)
        self.assertEqual(x.tree_str(), '+\n  3\n  >=\n    1\n    2\n')


class LessEqualTest(unittest.TestCase):
    """
    Tests myokit.LessEqual.
    """
    def test_eval(self):
        # Test LessEqual.eval().
        x = myokit.LessEqual(myokit.Number(1), myokit.Number(1))
        self.assertTrue(x.eval())
        x = myokit.LessEqual(myokit.Number(1), myokit.Number(2))
        self.assertTrue(x.eval())
        x = myokit.LessEqual(myokit.Number(2), myokit.Number(1))
        self.assertFalse(x.eval())

    def test_tree_str(self):
        # Test LessEqual.tree_str().
        x = myokit.LessEqual(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), '<=\n  1\n  2\n')
        x = myokit.Plus(myokit.Number(3), x)
        self.assertEqual(x.tree_str(), '+\n  3\n  <=\n    1\n    2\n')


class AndTest(unittest.TestCase):
    """
    Tests myokit.And.
    """
    def test_eval(self):
        # Test And.eval().
        x = myokit.And(myokit.Number(1), myokit.Number(1))
        self.assertTrue(x.eval())
        x = myokit.And(myokit.Number(0), myokit.Number(2))
        self.assertFalse(x.eval())

    def test_eval_unit(self):
        # Test And.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('1')
        y = c.add_variable('y')
        y.set_rhs('1')
        z = c.add_variable('z')
        z.set_rhs('x and y')

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless', z.rhs().eval_unit)
        y.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless', z.rhs().eval_unit)
        x.set_unit(myokit.units.dimensionless)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless', z.rhs().eval_unit)
        y.set_unit(myokit.units.dimensionless)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionles', z.rhs().eval_unit, s)
        y.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionles', z.rhs().eval_unit, s)
        x.set_unit(myokit.units.dimensionless)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionles', z.rhs().eval_unit, s)
        y.set_unit(myokit.units.dimensionless)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test And.tree_str().
        x = myokit.And(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), 'and\n  1\n  2\n')
        x = myokit.Plus(myokit.Number(3), x)
        self.assertEqual(x.tree_str(), '+\n  3\n  and\n    1\n    2\n')


class OrTest(unittest.TestCase):
    """
    Tests myokit.Or.
    """
    def test_eval(self):
        # Test Or.eval().
        x = myokit.Or(myokit.Number(1), myokit.Number(1))
        self.assertTrue(x.eval())
        x = myokit.Or(myokit.Number(0), myokit.Number(2))
        self.assertTrue(x.eval())
        x = myokit.Or(myokit.Number(0), myokit.Number(0))
        self.assertFalse(x.eval())

    def test_eval_unit(self):
        # Test Or.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('1')
        y = c.add_variable('y')
        y.set_rhs('1')
        z = c.add_variable('z')
        z.set_rhs('x or y')

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless', z.rhs().eval_unit)
        y.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless', z.rhs().eval_unit)
        x.set_unit(myokit.units.dimensionless)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless', z.rhs().eval_unit)
        y.set_unit(myokit.units.dimensionless)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionles', z.rhs().eval_unit, s)
        y.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionles', z.rhs().eval_unit, s)
        x.set_unit(myokit.units.dimensionless)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionles', z.rhs().eval_unit, s)
        y.set_unit(myokit.units.dimensionless)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        y.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

    def test_tree_str(self):
        # Test Or.tree_str().
        x = myokit.Or(myokit.Number(1), myokit.Number(2))
        self.assertEqual(x.tree_str(), 'or\n  1\n  2\n')
        x = myokit.Plus(myokit.Number(3), x)
        self.assertEqual(x.tree_str(), '+\n  3\n  or\n    1\n    2\n')


class NotTest(unittest.TestCase):
    """
    Tests myokit.Not.
    """
    def test_code(self):
        # Test Not.code().
        x = myokit.Not(myokit.Number(1))
        self.assertEqual(x.code(), 'not 1')
        x = myokit.Not(myokit.Equal(myokit.Number(1), myokit.Number(1)))
        self.assertEqual(x.code(), 'not (1 == 1)')

    def test_eval(self):
        # Test Not.eval().
        x = myokit.Not(myokit.Number(1))
        self.assertFalse(x.eval())
        x = myokit.Not(myokit.Number(0))
        self.assertTrue(x.eval())

    def test_eval_unit(self):
        # Test Not.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        x = c.add_variable('x')
        x.set_rhs('1')
        z = c.add_variable('z')
        z.set_rhs('not x')

        # Test in tolerant mode
        self.assertEqual(z.rhs().eval_unit(), None)
        x.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionless', z.rhs().eval_unit)
        x.set_unit(myokit.units.dimensionless)
        self.assertEqual(z.rhs().eval_unit(), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(myokit.units.ampere)
        self.assertRaisesRegex(
            myokit.IncompatibleUnitError, 'dimensionles', z.rhs().eval_unit, s)
        x.set_unit(myokit.units.dimensionless)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)
        x.set_unit(None)
        self.assertEqual(z.rhs().eval_unit(s), myokit.units.dimensionless)

    def test_polish(self):
        # Test Not._polish().
        x = myokit.Not(myokit.Number(1))
        self.assertEqual(x._polish(), 'not 1')
        x = myokit.Not(myokit.Equal(myokit.Number(1), myokit.Number(1)))
        self.assertEqual(x._polish(), 'not == 1 1')


class IfTest(unittest.TestCase):
    """
    Tests myokit.If.
    """
    def test_creation(self):
        # Test creation plus some accessor methods.

        cond = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then = myokit.Number(10)
        else_ = myokit.Number(20)
        if_ = myokit.If(cond, then, else_)

        # Test condition()
        self.assertEqual(if_.condition(), cond)

        # Test is_conditional()
        self.assertTrue(if_.is_conditional())

    def test_eval(self):
        # Test If.eval().

        cond = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then = myokit.Number(10)
        else_ = myokit.Number(20)
        if_ = myokit.If(cond, then, else_)
        self.assertEqual(if_.eval(), 10)

        cond = myokit.Equal(myokit.Number(1), myokit.Number(2))
        if_ = myokit.If(cond, then, else_)
        self.assertEqual(if_.eval(), 20)

    def test_eval_unit(self):
        # Test If.eval_unit().

        # Mini model
        m = myokit.Model()
        c = m.add_component('c')
        v1 = c.add_variable('v1')
        v2 = c.add_variable('v2')
        v3 = c.add_variable('v3')
        v4 = c.add_variable('v4')
        v1.set_rhs('1 == 1')
        v2.set_rhs(2)
        v3.set_rhs(3)
        v4.set_rhs('if(v1, v2, v3)')
        z = v4.rhs()

        # Test in tolerant mode
        self.assertEqual(z.eval_unit(), None)
        v2.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        v3.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        v2.set_unit(None)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        v3.set_unit(None)
        self.assertEqual(z.eval_unit(), None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.eval_unit(s), myokit.units.dimensionless)
        v2.set_unit(myokit.units.ampere)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        v3.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(s), myokit.units.ampere)
        v2.set_unit(None)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        v3.set_unit(None)
        self.assertEqual(z.eval_unit(s), myokit.units.dimensionless)

    def test_piecewise_conversion(self):
        # Test If.piecewise().
        cond = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then = myokit.Number(10)
        else_ = myokit.Number(20)
        if_ = myokit.If(cond, then, else_)
        pw = if_.piecewise()
        self.assertEqual(if_.eval(), pw.eval())

        cond = myokit.Equal(myokit.Number(1), myokit.Number(2))
        if_ = myokit.If(cond, then, else_)
        pw = if_.piecewise()
        self.assertEqual(if_.eval(), pw.eval())

    def test_value(self):
        # Test If.value().
        cond = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then = myokit.Number(10)
        else_ = myokit.Number(20)
        if_ = myokit.If(cond, then, else_)
        self.assertEqual(if_.value(True), then)
        self.assertEqual(if_.value(False), else_)


class PiecewiseTest(unittest.TestCase):
    """
    Tests myokit.Piecewise.
    """
    def test_creation(self):
        # Test Piecewise creation plus some accessor methods.

        # Like an if
        cond1 = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then1 = myokit.Number(10)
        final = myokit.Number(99)
        pw = myokit.Piecewise(cond1, then1, final)

        # Test is_conditional()
        self.assertTrue(pw.is_conditional())

        # Test conditions()
        c = list(pw.conditions())
        self.assertEqual(len(c), 1)
        self.assertEqual(c[0], cond1)

        # Test pieces()
        p = list(pw.pieces())
        self.assertEqual(len(p), 2)
        self.assertEqual(p[0], then1)
        self.assertEqual(p[1], final)

        # Like a big if
        cond1 = myokit.Equal(myokit.Number(2), myokit.Number(1))
        then1 = myokit.Number(1)
        cond2 = myokit.Equal(myokit.Number(3), myokit.Number(1))
        then2 = myokit.Number(2)
        cond3 = myokit.Equal(myokit.Number(1), myokit.Number(1))
        then3 = myokit.Number(3)
        final = myokit.Number(99)
        pw = myokit.Piecewise(cond1, then1, cond2, then2, cond3, then3, final)

        # Test conditions()
        c = list(pw.conditions())
        self.assertEqual(len(c), 3)
        self.assertEqual(c[0], cond1)
        self.assertEqual(c[1], cond2)
        self.assertEqual(c[2], cond3)

        # Test pieces()
        p = list(pw.pieces())
        self.assertEqual(len(p), 4)
        self.assertEqual(p[0], then1)
        self.assertEqual(p[1], then2)
        self.assertEqual(p[2], then3)
        self.assertEqual(p[3], final)

        # Wrong number of operands
        self.assertRaisesRegex(
            myokit.IntegrityError, 'odd number', myokit.Piecewise,
            cond1, then1)
        self.assertRaisesRegex(
            myokit.IntegrityError, 'odd number', myokit.Piecewise,
            cond1, then1, cond2, then2)

        # Wrong number of operands
        self.assertRaisesRegex(
            myokit.IntegrityError, '3 or more', myokit.Piecewise, cond1)

    def test_eval(self):
        # Test Piecewise.eval().
        ct = myokit.Equal(myokit.Number(1), myokit.Number(1))
        cf = myokit.Equal(myokit.Number(1), myokit.Number(2))
        then1 = myokit.Number(1)
        then2 = myokit.Number(2)
        then3 = myokit.Number(3)
        final = myokit.Number(99)

        pw = myokit.Piecewise(cf, then1, cf, then2, cf, then3, final)
        self.assertEqual(pw.eval(), 99)
        pw = myokit.Piecewise(cf, then1, cf, then2, ct, then3, final)
        self.assertEqual(pw.eval(), 3)
        pw = myokit.Piecewise(cf, then1, ct, then2, ct, then3, final)
        self.assertEqual(pw.eval(), 2)
        pw = myokit.Piecewise(ct, then1, ct, then2, ct, then3, final)
        self.assertEqual(pw.eval(), 1)
        pw = myokit.Piecewise(ct, then1, cf, then2, ct, then3, final)
        self.assertEqual(pw.eval(), 1)
        pw = myokit.Piecewise(ct, then1, ct, then2, cf, then3, final)
        self.assertEqual(pw.eval(), 1)
        pw = myokit.Piecewise(ct, then1, cf, then2, cf, then3, final)
        self.assertEqual(pw.eval(), 1)
        pw = myokit.Piecewise(cf, then1, cf, then2, cf, then3, final)
        self.assertEqual(pw.eval(), 99)

    def test_eval_unit(self):
        # Test Piecewise.eval_unit().
        # Mini model
        m = myokit.Model()
        comp = m.add_component('comp')

        # Create conditions
        c1 = comp.add_variable('c1')
        c2 = comp.add_variable('c2')
        c1.set_rhs('1 == 2')
        c2.set_rhs('1 == 2')

        # Create values
        t1 = comp.add_variable('t1')
        t2 = comp.add_variable('t2')
        t3 = comp.add_variable('t3')
        t1.set_rhs(1)
        t2.set_rhs(2)
        t3.set_rhs(3)

        # Create piecewise
        pw = comp.add_variable('pw')
        pw.set_rhs('piecewise(c1, t1, c2, t2, t3)')
        z = pw.rhs()

        # Test in tolerant mode
        self.assertEqual(z.eval_unit(), None)
        t1.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        t2.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        t3.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        t1.set_unit(None)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        t2.set_unit(None)
        self.assertEqual(z.eval_unit(), myokit.units.ampere)
        t3.set_unit(None)
        self.assertEqual(z.eval_unit(), None)
        t2.set_unit(myokit.units.Newton)
        t3.set_unit(myokit.units.volt)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit)
        t1.set_unit(None)
        t2.set_unit(None)
        t3.set_unit(None)

        # Test in strict mode
        s = myokit.UNIT_STRICT
        self.assertEqual(z.eval_unit(s), myokit.units.dimensionless)
        t1.set_unit(myokit.units.ampere)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        t2.set_unit(myokit.units.ampere)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        t3.set_unit(myokit.units.ampere)
        self.assertEqual(z.eval_unit(s), myokit.units.ampere)
        t1.set_unit(None)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        t2.set_unit(None)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)
        t3.set_unit(None)
        self.assertEqual(z.eval_unit(s), myokit.units.dimensionless)
        t2.set_unit(myokit.units.Newton)
        t3.set_unit(myokit.units.volt)
        self.assertRaises(myokit.IncompatibleUnitError, z.eval_unit, s)


class EquationTest(unittest.TestCase):
    """
    Tests :class:`myokit.Equation` (which is not strictly speaking a part of
    the equation system).
    """
    def test_creation(self):
        # Test creation of equations.
        lhs = myokit.Name('x')
        rhs = myokit.Number('3')
        myokit.Equation(lhs, rhs)

    def test_code(self):
        # Test :meth:`Equation.code()`.
        eq = myokit.Equation(myokit.Name('x'), myokit.Number('3'))
        self.assertEqual(eq.code(), 'str:x = 3')
        self.assertEqual(eq.code(), str(eq))

    def test_clone(self):
        # Test equation cloning
        eq1 = myokit.Equation(myokit.Name('x'), myokit.Name('y'))
        eq2 = myokit.Equation(myokit.Name('y'), myokit.Name('x'))
        self.assertEqual(eq1.clone(), eq1)
        self.assertEqual(eq1, eq2.clone(subst={
            myokit.Name('x'): myokit.Name('y'),
            myokit.Name('y'): myokit.Name('x'),
        }))

    def test_eq(self):
        # Test equality checking.
        eq1 = myokit.Equation(myokit.Name('x'), myokit.Number('3'))
        eq2 = myokit.Equation(myokit.Name('x'), myokit.Number('3'))
        self.assertEqual(eq1, eq2)
        self.assertEqual(eq2, eq1)
        self.assertFalse(eq1 != eq2)

        eq2 = myokit.Equation(myokit.Name('x'), myokit.Number('4'))
        self.assertNotEqual(eq1, eq2)
        self.assertNotEqual(eq2, eq1)
        self.assertTrue(eq1 != eq2)

        eq2 = myokit.Equation(myokit.Name('y'), myokit.Number('3'))
        self.assertNotEqual(eq1, eq2)
        self.assertNotEqual(eq2, eq1)

        eq2 = myokit.Equal(myokit.Name('x'), myokit.Number('3'))
        self.assertNotEqual(eq1, eq2)
        self.assertNotEqual(eq2, eq1)

        eq2 = 'hi'
        self.assertNotEqual(eq1, eq2)
        self.assertNotEqual(eq2, eq1)

    def test_hash(self):
        # Test that equations can be hashed.
        # No exception = pass
        hash(myokit.Equation(myokit.Name('x'), myokit.Number('3')))

    def test_iter(self):
        # Test iteration over an equation.
        lhs = myokit.Name('x')
        rhs = myokit.Number('3')
        eq = myokit.Equation(lhs, rhs)
        i = iter(eq)
        self.assertEqual(next(i), lhs)
        self.assertEqual(next(i), rhs)
        self.assertEqual(len(list(eq)), 2)

    def test_str_and_repr(self):
        # Test string conversion
        x = myokit.Model('m').add_component('c').add_variable('x')
        eq1 = myokit.Equation(myokit.Name(x), myokit.Number('3'))
        self.assertEqual(str(eq1), 'c.x = 3')
        self.assertEqual(repr(eq1), '<Equation c.x = 3>')


class UserFunctionTest(unittest.TestCase):
    """
    Tests :class:`UserFunction`.
    """
    def test_user_function(self):
        # Test :class:`UserFunction` creation and methods.

        # Create without arguments
        f = myokit.UserFunction('bert', [], myokit.Number(12))
        args = list(f.arguments())
        self.assertEqual(len(args), 0)
        self.assertEqual(f.convert([]), myokit.Number(12))

        # Create with one argument
        f = myokit.UserFunction(
            'x', [myokit.Name('a')], myokit.parse_expression('1 + a'))
        self.assertEqual(len(list(f.arguments())), 1)
        args = {myokit.Name('a'): myokit.Number(3)}
        self.assertEqual(f.convert(args).eval(), 4)

        # Create with two argument
        f = myokit.UserFunction(
            'x', [myokit.Name('a'), myokit.Name('b')],
            myokit.parse_expression('a + b'))
        self.assertEqual(len(list(f.arguments())), 2)
        args = {
            myokit.Name('a'): myokit.Number(3),
            myokit.Name('b'): myokit.Number(4)
        }
        self.assertEqual(f.convert(args), myokit.parse_expression('3 + 4'))

        # Call with wrong arguments
        del(args[myokit.Name('a')])
        self.assertRaisesRegex(
            ValueError, 'Wrong number', f.convert, args)
        args[myokit.Name('c')] = myokit.Number(100)
        self.assertRaisesRegex(
            ValueError, 'Missing input argument', f.convert, args)


if __name__ == '__main__':
    unittest.main()
