def test_resolve():
    '''
    Test resolving external identifiers.
    '''
    I = 3 * mV
    tau = 5 * ms
    expr = Expression('-(v + I) / tau')
    namespace = expr.resolve(['v'])
    assert not 'v' in namespace
    assert namespace['I'] == I and namespace['tau'] == tau
    
    another_I = 5 * mV
    expr = Expression('-(v + I) / tau', namespace={'I' : another_I})
    # tau is not defined, the namespace should be exhaustive
    assert_raises(ValueError, lambda: expr.resolve(['v']))
    expr = Expression('-(v + I) / tau', namespace={'I' : another_I,
                                                   'tau': tau})
    # Now it should work
    namespace = expr.resolve(['v'])
    assert namespace['I'] == another_I and namespace['tau'] == tau
    
    # test resolution of units not present in any namespace
    expr = Expression('v * amp * ohm')
    namespace = expr.resolve(['v'])
    assert namespace['ohm'] is brian2.ohm and namespace['amp'] is brian2.amp
def test_resolution_warnings():
    '''
    Test that certain calls to resolve generate a warning.
    '''
    I = 3 * mV
    tau = 5 * ms
    another_I = 5 * mV
    # Only specifying part of the namespace
    expr = Expression('-(v + I) / tau', namespace={'I' : another_I},
                      exhaustive=False)
    
    # make sure this triggers a warning (the 'I' in the namespace shadows the
    # I variable defined above
    with catch_logs() as logs:
        namespace = expr.resolve(['v'])
        assert len(logs) == 1
        assert logs[0][0] == 'WARNING' 
        assert logs[0][1].endswith('resolution_conflict')
        assert namespace['I'] == another_I and namespace['tau'] == tau
    
    freq = 300 * Hz
    t = 5 * second
    # This expression treats t as a special variable and is not actually using
    # the t above!
    expr = Expression('sin(2 * 3.141 * freq * t)')
    with catch_logs() as logs:
        namespace = expr.resolve([])
        assert len(logs) == 1
        assert logs[0][0] == 'WARNING' 
        assert logs[0][1].endswith('resolution_conflict')            
        assert namespace['freq'] == freq and not 't' in namespace

    I = 3 * mV
    tau = 5 * ms    
    expr = Expression('-(v + I)/ tau')
    # If we claim that I is an internal variable, it shadows the variable
    # defined in the local namespace -- this should trigger a warning
    with catch_logs() as logs:
        namespace = expr.resolve(['v', 'I'])
        assert len(logs) == 1
        assert logs[0][0] == 'WARNING' 
        assert logs[0][1].endswith('resolution_conflict')
        assert namespace['tau'] == tau and not 'I' in namespace
    
    # A more extreme example: I is defined above, but also in the namespace and
    # is claimed to be an internal variable
    expr = Expression('-(v + I)/ tau', namespace={'I': 5 * mV},
                      exhaustive=False)
    with catch_logs() as logs:
        namespace = expr.resolve(['v', 'I'])
        assert len(logs) == 1
        assert logs[0][0] == 'WARNING' 
        assert logs[0][1].endswith('resolution_conflict')
        assert namespace['tau'] == tau and not 'I' in namespace
def test_expr_units():
    '''
    Test getting/checking the units of an expression.
    '''
    tau = 5 * ms
    expr = Expression('-v / tau', namespace={'tau': tau})
    expr.resolve(['v'])
    expr.check_units(volt / second, {'v': volt})
    assert_raises(DimensionMismatchError, lambda: expr.check_units(volt / second,
                                                                   {'v': second}))
    assert_raises(DimensionMismatchError, lambda: expr.check_units(volt,
                                                                   {'v': volt}))
    assert expr.get_dimensions({'v': volt}) == get_dimensions(volt / second)
def test_split_stochastic():
    tau = 5 * ms
    expr = Expression('(-v + I) / tau')
    expr.resolve(['v', 'I'])
    # No stochastic part
    assert expr.split_stochastic() == (expr, None)
    
    expr = Expression('(-v + I) / tau + sigma*xi/tau**.5')
    expr.resolve(['v', 'I', 'sigma'])
    non_stochastic, stochastic = expr.split_stochastic()
    assert 'xi' in stochastic.identifiers
    assert sympy_equals(non_stochastic.code, '(-v + I) / tau')
    assert sympy_equals(stochastic.code, 'sigma*xi/tau**.5')
    
    expr = Expression('-v / tau + 1 / xi')
    assert_raises(ValueError, expr.split_stochastic)